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()
}
}
Today I noticed something weird using Entity Framework Core. In the AddNewBarToFoo
method of SomeClass
I want to add a new Bar to a collection of Foos. Originally I used Option 1, but I noticed that, after the call to SaveChanges
, foo.Bars would contain the new Bar twice.
I noticed that removing the call to SaveChanges
would not add the second Bar and still persist the Bar correctly. Using Option 2 works as expected too.
I found this quite strange behavior and upon investigating a little I found that the reason for this is that I overrode the Equals
method of Bar and that I used the Id to check for equality.
Removing the Id comparison from the Equals
method and otherwise using Option 1 works as expected: Foo.Bars contains the new Bar only once.
I actually have two questions now:
What is the reason Entity Framework adds the same Bar twice?
I suppose it adds the new Bar to the context once, giving it an Id and then encounters it again (somehow?) but this instance still has Id 0 and thus is considered different than the first per myEquals
method.Was I wrong to use the Id in my overridden
Equals
method? Or in the code for adding a new Bar to a Foo? Is it bad practice to overrideEquals
?
In short: what is the 'correct' way to do what I tried to do?