Вот простой объект:Entity Framework обновление виртуальной собственности напрямую, без создания новой записи
public class Customer : Entity
{
public virtual Location Location { get; set; }
}
Теперь предположим, что у нас есть клиент уже:
var customer = new Customer() {Location = new Location("China")};
и теперь мы хотим обновить его местоположение:
var customer = context.Customers.First(x => x.Location.Country == "China");
customer.Location = new Location("America");
context.SaveChanges();
и теперь, когда я смотрю базу данных, запись местоположения «Китай» не была удалена: В базе данных теперь имеется две записи записей местоположений с одной записью клиента.
Причины этого вопроса является то, что я использую виртуальное ключевое слово на собственности Customer.Location, и когда я запрашиваю объект клиента из базы данных я не использовал Включить метод для загрузки Местонахождение объекта, и я также не использовал доступа к ленивой загрузке. Поэтому EF не может отслеживать и знать China
Объект местоположения должен быть удален.
Я думаю, что подход, который я использовал для виртуального свойства обновления, соответствует интуиции. Я хочу обновить свойство, а затем просто использовать инструкцию по обновлению «entity.xxx = ...», добавить принудительно использовать некоторый доступ к вызову свойства или метода при загрузке «entity.xxx» не является интуитивным.
Так что я ищу лучший способ заменить виртуальную собственность объекта напрямую. Какие-либо предложения?
Solutions обновить
Я найти два способа сделать это легко,
Сначала вы можете использовать Identifying relation (рекомендуем).
Другим способом вы можете использовать ObjectContext.DeleteObject метод, ниже приведен пример кода:
public static class EFCollectionHelper
{
public static void UpdateCollection<T, TValue>(this T target,
Expression<Func<T, IEnumerable<TValue>>> memberLamda, TValue value)where T : Entity
{
var memberSelectorExpression = (MemberExpression)memberLamda.Body;
var property = (PropertyInfo)memberSelectorExpression.Member;
var oldCollection = memberLamda.Compile()(target);
oldCollection.ClearUp();
property.SetValue(target, value, null);
}
public static void ClearUp<T>(this IEnumerable<T> collection)
{
//Convert your DbContext to IObjectContextAdapter
var objContext = ((IObjectContextAdapter) Program.DbContext).ObjectContext;
for (int i = 0; i < collection.Count(); i++)
{
objContext.DeleteObject(collection.ElementAt(i));
}
}
}
И тогда вы можете просто написать код, как:
customer.UpdateCollection(x => x.Locations, null);
Когда вы говорите, «запись о местоположении„Китай“не был удален: база данных теперь имеет две записи местоположение» сделать вас означает, что в базе данных теперь есть две записи клиентов, одна с Китаем и одна с Америкой в качестве локаций? Или вы имеете в виду, что теперь есть две записи местоположения, как кажется, вы говорите. Если в настоящее время есть две записи местоположения, это не обязательно неправильно. Если ваша таблица местоположений представляет собой таблицу типа поиска, которая должна иметь возможные местоположения, теперь у вас есть два возможных местоположения в таблице, и ваша запись о клиенте теперь правильна, поскольку она указывает на Америку (Америка). – DWright
@DWright, извините за путаницу, база данных теперь имеет две ассоциации записей местоположения с одной записью клиента, и да, клиент. Место укажет на Америку, но в базе данных он будет генерировать запись местоположения каждый раз, когда я использую «клиент». Местоположение = новое местоположение() для обновления местоположения клиента. – ilovezcd
И еще один способ, если виртуальное свойство представляет собой коллекцию, затем используйте «customer.collection = xxx ...», чтобы вставить новую коллекцию в базу данных, а в следующий раз, когда вы получите клиента из базы данных, «customer.collection» будет двойной на самом деле. – ilovezcd