EF4 сохранить сложный отдельный объект графа
У меня есть следующая модель EF на основе EntityObject (свойства записаны здесь как поля для поддержания чистоты кода):
Booking
{
int BookingID;
EntityCollection<BookingCustomer> BookingCustomers;
string Notes;
}
BookingCustomer
{
Customer Customer;
Booking Booking;
int CustomerID;
int BookingID;
string Notes;
}
Customer
{
int CustomerID;
string Name;
}
Я загружаю граф объекта отдельно:
Booking existingBooking;
using(MyContext ctx = new MyContext())
{
ctx.Bookings.MergeOption = MergeOption.NoTracking;
ctx.BookingCustomers.MergeOption = MergeOption.NoTracking;
ctx.Customers.MergeOption = MergeOption.NoTracking;
existingBooking = ctx.Bookings
.Include("BookingCustomers")
.Include("BookingCustomers.Customer")
.First();
}
Изменение бронирования и данных клиента:
existingBooking.Notes = "Modified";
existingBooking.BookingCustomers.First().Name += " Edited";
Сохранение этого:
using(MyContext ctx = new MyContext())
{
ctx.Bookings.Attach(existingBooking);
ctx.ObjectStateManager.GetObjectStateEntry(existingBooking ).SetModified();
ctx.Refresh(RefreshMode.ClientWins, existingBooking);
ctx.SaveChanges();
}
Я получаю новую запись о клиенте (вместо существующей записи).
Я также попробовал это:
using(MyContext ctx = new MyContext())
{
ctx.Customers.Attach(existingBooking.BookingCustomers.First());
ctx.ObjectStateManager.GetObjectStateEntry(existingBooking.BookingCustomers.First()).SetModified();
ctx.Refresh(RefreshMode.ClientWins, existingBooking.BookingCustomers.First());
ctx.Bookings.Attach(existingBooking);
ctx.ObjectStateManager.GetObjectStateEntry(existingBooking ).SetModified();
ctx.Refresh(RefreshMode.ClientWins, existingBooking);
ctx.SaveChanges();
}
но получить исключение на линии ctx.Customers.Attach(existingBooking.BookingCustomers.First());
:
System.InvalidOperationException: A referential integrity constraint violation occurred: The property values that define the referential constraints are not consistent between principal and dependent objects in the relationship.
Как я могу заставить это работать?
2 ответа
Это не освежает. Если вы измените график в отдельном состоянии, EF не сможет найти, какие изменения вы сделали. Вы должны вручную установить состояние каждого измененного объекта или отношения. Attach
поместит весь график в Unchanged
состояние и ChangeObjectState
влияет только на один объект в графе.
Вы обнаружили, что самый простой способ - снова загрузить весь график во время сохранения и вручную объединить ваши изменения с прикрепленным графиком. Особенно, если вы хотите удалить некоторые отношения / сущности или выполнять сложные операции со многими отношениями ко многим, это будет удобно.
Ладислав прав. Тем не менее, есть еще один вариант, который вы должны рассмотреть, который решил бы эту проблему и все же позволил бы вам сохранить детализированную модель - POCO с самостоятельным отслеживанием. Существует шаблон T4 (он либо связан с VS2010, либо доступен для загрузки), который позволяет графу объектов отслеживать его состояние (включая добавление / удаление объектов на графике, а также то, какие свойства объекта были изменены), чтобы вы могли может заново прикрепить график, внеся изменения; EF4 определит изменения и применит их к менеджеру состояния объекта.