У меня есть сущность Contracts вот так:
public partial class Contracts
{
public Contracts()
{
ListKindWorks = new HashSet<ListKindWorks>();
ListSubjects = new HashSet<ListSubjects>();
}
public int Id { get; set; }
public string Num { get; set; }
public DateTime DateConclusion { get; set; }
public int Worker { get; set; }
public DateTime DateStartWork { get; set; }
public DateTime DateEndWork { get; set; }
public float Salary { get; set; }
public virtual Workers WorkerNavigation { get; set; }
public virtual ICollection<ListKindWorks> ListKindWorks { get; set; }
public virtual ICollection<ListSubjects> ListSubjects { get; set; }
}
И функция ShowUpdateDialog():
/// <summary>
/// Open dialog for update chosen Contract
/// </summary>
/// <param name = "c">chosen Contract</param>
internal void ShowUpdateDialog(Contracts c)
{
Contract = c;
using (ContractForm form = new ContractForm())
{
form.Fill(model.Data);
form.Fill(Contract);
form.Fill(model.GetUI(Mode.UPDATE));
if (form.ShowDialog() == DialogResult.OK)
{
bool result = true;
try
{
using (ModelContext context = new ModelContext())
{
context.Attach(Contract);
Contract = form.GetMainValues(Contract);
Contract = form.GetDetailValues(Contract);
context.SaveChanges();
}
}
catch (Exception ex)
{
result = false;
string msg = string.Format("Ошибка во время обновления записи в базе данных. Детали: {0}", ex.Message);
form.ShowError(msg);
}
if (result)
{
ContractUpdatedSuccessEvent?.Invoke(this, EventArgs.Empty);
}
}
}
}
Внешняя переменная:
public Contracts Contract { get; set; }
Он используется для того, чтобы не выделять память каждый раз и является общедоступным, чтобы в случае успешного обновления другой класс мог взять его и вставить в DataGridView. Поэтому я не обращаюсь к базе данных за текущими значениями записи, потому что данные поступают из DataGridView. Для отслеживания изменений используется context.Attach(Contract).
internal Contracts GetMainValues(Contracts c)
{
c.Num = tbNum.Text;
c.Salary = float.Parse(tbSalary.Text);
c.DateConclusion = dpDateConclusion.Value;
c.DateStartWork = dpDateStart.Value;
c.DateEndWork = dpDateEnd.Value;
Item item = (Item)cbWorker.SelectedItem;
c.Worker = item.Id;
return c;
}
internal Contracts GetDetailValues(Contracts c)
{
listKindWorks.Clear();
listSelectedSubjects.Clear();
foreach (int index in clbKindWork.CheckedIndices)
{
int id = ((Item)clbKindWork.Items[index]).Id;
ListKindWorks item = new ListKindWorks
{
IdContract = c.Id,
IdKindWork = id
};
listKindWorks.Add(item);
}
foreach (Item item in lbSelectedSubject.Items)
{
ListSubjects subject = new ListSubjects
{
IdContract = c.Id,
IdSubject = item.Id
};
listSelectedSubjects.Add(subject);
}
c.ListKindWorks = listKindWorks;
c.ListSubjects = listSelectedSubjects;
return c;
}
Моя проблема заключается в следующем:
Когда if (.. == DialogResult.OK) истинно, мне нужно обновить текущее Contract до новых значений из form следующим образом:
context.Attach(Contract);
Contract = form.GetMainValues(Contract);
Contract = form.GetDetailValues(Contract);
context.SaveChanges();
Но поэтому этот код должен быть в using (ContractForm..). В противном случае невозможно получить новые значения из form. Если я создам новую переменную, например Contracts, и отдельную функцию Update, например:
private void Update(Contracts c)
{
using (ModelContext context = new ModelContext())
{
context.Attach(Contract);
Contract = c;
context.SaveChanges();
}
}
Обновление значений из GetDetailValues() не происходит. Почему?
Могу ли я упростить этот код?
Обновлять:
Согласно коду из ответа Хенк Холтерман и моего private void Update(Contracts c):
изменил значения из GetMainValues(), но не из GetDetailValues()
@DevilSuichiro Аналогично. Без аттача, но с context.Entry(c).State = EntityState.Modified - изменены значения с GetMainValues(), но нет с GetDetailValues()
@DevilSuichiro тоже не помогает context.Entry(c).Collection(x => x.ListKindWorks).IsModified = true
.Collection().IsModified означает: коллекция изменена на другие значения, но вы не указали, что изменились ранее существующие записи. Вы должны выяснить, какие записи добавлены, какие удалены и какие изменены, и соответствующим образом установить состояние.
@DevilSuichiro смотрите первый код после My problem is as follows. Это работает правильно и просто. И любая попытка разделить получение новых данных и их обновление только усложняет весь код.





Я добавил в Contracts метод Update() и вызываю его после .Attach()
internal void Update(Contracts c)
{
this.Num = c.Num;
this.Salary = c.Salary;
this.Worker = c.Worker;
this.FullName = c.FullName;
this.DateConclusion = c.DateConclusion;
this.DateStartWork = c.DateStartWork;
this.DateEndWork = c.DateEndWork;
this.ListKindWorks = c.ListKindWorks;
this.ListSubjects = c.ListSubjects;
}
private void Update(Contracts oldValue, Contracts newValue)
{
using (ModelContext context = new ModelContext())
{
context.Attach(oldValue);
oldValue.Update(newValue);
// oldValue = newValue; // .Attach does not respond to this
context.SaveChanges();
}
}
.Attach прикрепляет объект в неизмененном состоянии, поэтому обновление не происходит. Вместо этого либо установите context.Entry(Contract), либо просто установите состояние сущностей как измененное.