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
的{{1}}方法中,我想向Foos集合中添加一个新的Bar。最初,我使用Option 1,但是我注意到,在调用SomeClass
之后,foo.Bars将两次包含新的Bar。
我注意到,删除对SaveChanges
的调用不会添加第二个Bar,并且仍然可以正确保留Bar。使用选项2也会按预期工作。
我发现这是一种非常奇怪的行为,经过一番调查,我发现这样做的原因是我取代了Bar的SaveChanges
方法,并且我使用了ID来检查是否相等。
从Equals
方法中删除ID比较,否则使用Option 1可以按预期工作:Foo.Bars仅包含一次新的Bar。
我现在实际上有两个问题:
实体框架两次添加相同栏的原因是什么?
我想它会一次将新的Bar添加到上下文中,为其提供一个ID,然后再次遇到它(以某种方式?),但是此实例仍然具有ID 0,因此,与我的Equals
方法中的第一个实例不同。
我在覆盖的Equals
方法中使用ID是否出错?还是在代码中向Foo添加新Bar?覆盖Equals
是不好的做法吗?
简而言之:做什么是我尝试做的“正确”方法?