В соответствии с этим билетом EF Core GitHub необходимо обновить свойства дочернего / вложенного / собственного типа, чтобы он правильно отслеживался.Предполагалось, что это будет исправлено в EF 2.1 (в настоящее время доступно только в качестве кандидата на выпуск), но, возможно, оно не было сделано.В 2.0.3 они обновили словесность исключения:
InvalidOperationException: экземпляр типа сущности 'Parent.Child # Child' не может быть отслежен, поскольку другой экземпляр с тем же значением ключа для {'ParentID '} уже отслеживается. При замене собственных объектов измените свойства без изменения экземпляра или сначала отсоедините предыдущую запись принадлежащего объекта.
Вторая часть этого сообщения заставит васбросить немного, если вы используете DDD.Это говорит о том, что вы должны обновить свойства дочерних / вложенных свойств непосредственно для EF, чтобы правильно отслеживать изменения (что нарушает DDD Value Objects как неизменные).Что касается комментария к ветке GitHub , здесь предлагается несколько обходных путей, подходящих для DDD, адаптированных под ваш код:
public void SetAddress(Address address)
{
Guard.AssertArgumentNotNull(address, nameof(address));
Address.UpdateFrom(address);
}
// And on Address:
internal void UpdateFrom(Address other)
{
Street = other.Street;
// ...
}
-OR-
Второй предложенный обходной путь выполняется путем отсоединения сущности, обновления экземпляра Address
и последующего его присоединения.Мне не очень повезло с этим обходным путем в моей реализации, но я опубликую его для будущих поколений.Возможно, вам повезет больше, чем мне.
context.Entry(employee.Address).State = EntityState.Detached;
employee.SetAddress(newAddress);
context.Entry(employee.Address).State = EntityState.Modified;
ОБНОВЛЕНИЕ
Я наконец нашел открытый билет с командой EF Core, который можно отследитьдля этого вопроса. В билете # 10551 конкретно указана проблема, которая по-прежнему остается открытой.Он определенно не попал в EF Core 2.1 и, похоже, был помещен в Backlog Milestone 3.0.Обратите внимание, что вы можете проголосовать за эту проблему, чтобы заставить команду EF Core уделять ей больше внимания.
ОБНОВЛЕНИЕ 2 В EF Core 2.2 представлен компонент Tracked Graph, который делает это намногобольше жидкостиЭто, однако, требует, чтобы все ваши объекты EF использовали идентификаторы, сгенерированные базой данных.Этот метод проверяет, установлен ли ключ объекта, а затем отмечает объект как измененный или добавленный.Это может быть расширено, чтобы включать удаления, но для моих целей я не хочу такого поведения.
internal void Upsert(object entity)
{
ChangeTracker.TrackGraph(entity, e =>
{
if (e.Entry.IsKeySet)
{
e.Entry.State = EntityState.Modified;
}
else
{
e.Entry.State = EntityState.Added;
}
});
#if DEBUG
foreach (var entry in ChangeTracker.Entries())
{
Debug.WriteLine($"Entity: {entry.Entity.GetType().Name} State: {entry.State.ToString()}");
}
#endif
}
Затем используйте context.Upsert(<YOUR ENTITY OBJECT>);
перед context.SaveChanges();
.