Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[52.14.150.55] |
|
Сообщ.
#1
,
|
|
|
Здравствуйте.
Суть: используя вышеперечисленные технологии, при чтении из базы данных связанных объектов после добавления, функция SingleOfDefault падает эксепшеном запрос содержит более одной записи. Подробности: 1. Описание сущностей: Есть 3 связанных сущности - клиенты, телефоны и комментарии: class Clients { public long Id { get; set; } public string Name { get; set; } public long RegionId { get; set; } public string Address { get; set; } public long Status { get; set; } public System.DateTime FirstCallDate { get; set; } public System.DateTime RecallDate { get; set; } public long Mark { get; set; } public virtual Regions Regions { get; set; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] public virtual ICollection<Comments> Comments { get; set; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] public virtual ICollection<Orders> Orders { get; set; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] public virtual ICollection<Telephones> Telephones { get; set; } } class Comments { public long Id { get; set; } public System.DateTime CommentDate { get; set; } public string CommentText { get; set; } public long ClientId { get; set; } public virtual Clients Clients { get; set; } } class Telephones { public long Id { get; set; } public string Telephone { get; set; } public string Info { get; set; } public long ClientId { get; set; } public virtual Clients Clients { get; set; } } 2. Используемый код Что именно происходит: добавляю клиента, к нему номер телефона и комментарий - все нормально. Редактирую этого клиента - добавляю к нему новый номер телефона - при вызове этого клиента функция SingleOfDefault падает эксепшеном запрос содержит более одной записи. Примечание: то же самое делаю с комментарием(т.е. к существующему клиенту добавляю комментарий) все нормально, не падает Код добавления(по сути одинаков для добавления комментария и телефона): _t.Telephone = textBoxTelephone.Text; _t.Info = textBoxInfo.Text; _t.ClientId = Convert.ToInt32(comboBoxClients.SelectedValue); using (var db = new DatabaseContext()) { // наличие или отсутствие следующих двух строк ничего не меняет var cln = db.Clients.SingleOrDefault(c => c.Id == _t.ClientId); _t.Clients = cln; db.Telephones.Add(_t); db.SaveChanges(); } по комментам: _com.ClientId = Convert.ToInt32(comboBoxClients.SelectedValue); _com.CommentDate = dateTimePickerOtherDate.Value; _com.CommentText = richTextBoxComment.Text; using (var db = new DatabaseContext()) { db.Comments.Add(_com); db.SaveChanges(); } После такого добавления вызывается функция: public static ClientSample GetTodayUpdatedClient(long clientId) { var dt = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day + 1); ClientSample _todayClient = null; using (var db = new DatabaseContext()) { var transactions = from c in db.Clients join r in db.Regions on c.RegionId equals r.Id /*join t in db.Telephones on c.Id equals t.ClientId*/ where c.RecallDate < dt && c.Id == clientId && c.Status == (int)ClientStatus.Actual select new ClientSample { ClientId =c.Id, ClientName = c.Name, RegionName = r.RegionName, Status = c.Status, FirstCallDate = c.FirstCallDate, RecallDate = c.RecallDate, Mark = c.Mark, //TelList = c.Telephones.ToList() }; if (transactions != null) _todayClient = transactions.SingleOrDefault(); } if(_todayClient != null) { using (var db = new DatabaseContext()) { Clients tmpCl = db.Clients.Where(c => c.Id == _todayClient.ClientId).SingleOrDefault(); if(tmpCl != null) _todayClient.TelList = tmpCl.Telephones.ToList(); } } return _todayClient; } в таком варианте эксепшн не падает, но после перезагрузки проги появляется пару идентичных записей public static ClientSample GetTodayUpdatedClient(long clientId) { var dt = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day + 1); ClientSample _todayClient = null; using (var db = new DatabaseContext()) { var transactions = from c in db.Clients join r in db.Regions on c.RegionId equals r.Id join t in db.Telephones on c.Id equals t.ClientId where c.RecallDate < dt && c.Id == clientId && c.Status == (int)ClientStatus.Actual select new ClientSample { ClientId =c.Id, ClientName = c.Name, RegionName = r.RegionName, Status = c.Status, FirstCallDate = c.FirstCallDate, RecallDate = c.RecallDate, Mark = c.Mark, TelList = c.Telephones.ToList() }; if (transactions != null) _todayClient = transactions.SingleOrDefault(); } return _todayClient; } в этом варианте падает на SingleOrDefault. Также, появление дублирующихся записей наблюдается, если добавлять нового клиента с несколькими телефонами: _c.Name = textBoxName.Text; _c.RegionId = Convert.ToInt32(comboBoxRegion.SelectedValue); _c.Address = textBoxAddress.Text; _c.Mark = Convert.ToInt32(comboBoxMark.SelectedValue); _c.FirstCallDate = dateTimePickerFirstCall.Value; _c.RecallDate = dateTimePickerRecall.Value; _c.Status = Convert.ToInt32(comboBoxStatus.SelectedValue); if (_isAdd) { using (var db = new DatabaseContext()) { db.Clients.Add(_c); db.SaveChanges(); } using (var db = new DatabaseContext()) { //_c = db.Clients.Last(); db.Clients.Attach(_c); } } else { if (_wasClChanged) { using (var db = new DatabaseContext()) { db.Clients.Attach(_c); db.Entry(_c).State = EntityState.Modified; db.SaveChanges(); } } } bool wasTelUpdate = false; foreach (Telephones tl in _telephonesOfCurClient) { if (tl.ClientId != _c.Id) { tl.ClientId = _c.Id; wasTelUpdate = true; } } if (wasTelUpdate) { using (var db = new DatabaseContext()) { foreach (Telephones tl in _telephonesOfCurClient) { if (tl.Id == -1) { db.Telephones.Add(tl); } } db.SaveChanges(); } } bool wasCommUpdate = false; foreach (Comments cm in _commentsOfCurrentClient) { if (cm.ClientId != _c.Id) { cm.ClientId = _c.Id; wasCommUpdate = true; } } if (wasCommUpdate) { using (var db = new DatabaseContext()) { foreach (Comments cm in _commentsOfCurrentClient) { if (cm.Id == -1) { db.Comments.Add(cm); } } db.SaveChanges(); } } Опять-же, с несколькими комментами если добавлять - все нормально. 3. Итог: можно переписать функцию выбора, как в случае с не падающей singleordefault, но очень смущают эти дублирующие записи при кросстабличной выборке. Подскажите, пожалуйста, в чем может быть проблема ? За рекомендации по оптимизации кода тоже буду благодарен. Дополнительная информация к размышлению: - в таблицах базы данных повторяемых строк нет - проблема возникает при формировании промежуточного класса ClientSample после добавления 2 и более телефона к клиенту - повторяемых записей будет столько, сколько добавленных телефонов (к примеру, я добавляю 3 номера телефона к клиенту, тогда будет 3 идентичных на вид записи) - проверка методом Equals показала странную штуку: взял 2 идентичных на вид объекта, они не эквивалентны, взял их списки телефонов они не эквивалентны, по отдельности сравнил между собой соответствующие телефоны - они эквивалентны. Получается, разные ссылки на одни и те же данные, почему ? |
Сообщ.
#2
,
|
|
|
Разобрался.
Проблема была в правильности составления запроса к базе данных, а именно: var dt = new DateTime( DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day+1); List<ClientSample> _todayClientsList = null; using (var db = new DatabaseContext()) { var transactions = from c in db.Clients join r in db.Regions on c.RegionId equals r.Id join t in db.Telephones on c.Id equals t.ClientId // лишняя строка where c.RecallDate < dt && c.Status == (int)ClientStatus.Actual select new ClientSample { ClientId = c.Id, ClientName = c.Name, RegionName = r.RegionName, Status = c.Status, FirstCallDate = c.FirstCallDate, RecallDate = c.RecallDate, Mark = c.Mark, TelList = c.Telephones.ToList() }; if (transactions != null) _todayClientsList = transactions.ToList(); else _todayClientsList = new List<ClientSample>(); Этот джоин лишний. Как я предполагаю, этой лишней строкой я ставил в соответствие каждый номер телефона клиенту, т.е. делал связь 1 к 1(?), что и генерировало мне одного и того же клиента по количеству всех его телефонов. |