public class Foo
{
public int Id { get; set; }
public ICollection<Bar> Bars{get;set;}
}
public class Bar
{
public int Id { get; set; }
public int FooId { get; set; }
public override bool Equals(object obj)
{
var bar= obj as Bar;
return bar != null &&
Id == bar.Id;
}
public override int GetHashCode()
{
return 2108858624 + Id.GetHashCode();
}
}
public class SomeClass
{
DbContext _context = ...; // injected via DI
public void AddNewBarToFoo(int fooId)
{
// Option 1
// result: foo.Bars contains two items
Foo foo = _context.Foos
.Where(f => f.id == fooId)
.Include(f => f.Bars)
.FirstOrDefault();
foo.Bars.Add(new Bar());
_context.SaveChanges();
// Option 2
// result: foo.Bars contains one item
Bar bar = new Bar();
bar.FooId = FooId;
_context.Bars.Add(bar);
_context.SaveChanges();
// Option 3:
// Remove _context.SaveChanges() from Option 1
// Option 4:
// Remove the Id comparison from Bar.Equals()
}
}
Сегодня я заметил что-то странное, используя Entity Framework Core. В методе AddNewBarToFoo
SomeClass
я хочу добавить новый Bar в коллекцию Foos. Первоначально я использовал Вариант 1, но заметил, что после вызова SaveChanges
foo.Bars будет содержать новый Bar дважды.
Я заметил, что удаление вызова на SaveChanges
не добавит второй Бар и все еще сохранит Бар правильно. Использование варианта 2 также работает как ожидалось.
Я обнаружил, что это довольно странное поведение, и после небольшого исследования я обнаружил, что причина этого в том, что я отверг метод Equals
Бара и использовал Id для проверки на равенство.
Удаление сравнения идентификаторов из метода Equals
и использование в противном случае варианта 1 работает должным образом: Foo.Bars содержит новый Bar только один раз.
У меня сейчас два вопроса:
По какой причине Entity Framework добавляет один и тот же столбец дважды?
Я предполагаю, что он добавляет новый Bar в контекст один раз, давая ему Id, а затем снова встречает его (как-нибудь?), Но этот экземпляр все еще имеет Id 0 и, следовательно, считается отличным от первого для моего Equals
метода.
Был ли я неправ в использовании идентификатора в моем переопределенном Equals
методе? Или в коде для добавления нового бара в Foo? Это плохая практика переопределять Equals
?
Короче говоря: что такое «правильный» способ сделать то, что я пытался сделать?