c# - 为什么 EF 尝试使用单个或多个 SaveChanges() 插入实例两次?

标签 c# entity-framework entity-framework-6

我有以下类结构

class A { long Id { get; set; } ICollection<B> ManyB { get; set; } }
class B { long Id { get; set; } C { get; set; } }
class C { long Id { get; set; } Name { get; set; } }

用一个看起来像这样的实例图

object graph

当我添加一个 A 的实例时,它在 ManyB 中有两个不同的 B 实例引用相同的 C 实例,当我调用此代码时,EF 尝试插入两次 C:

var a = CreateItAsDescribedAbove();
context.Add(a)
context.SaveChanges();

上面的所有对象都是新的;也就是说,它们不是数据库中已有的实体。当我将代码更改为以下内容时,我仍然有相同的行为:

var a = CreateItAsDescribedAbove();
A.ManyB
   .Select(b => b.C)
   .DistinctBy(c => c.Id)
   .ForEach(c => context.Add(c));
context.SaveChanges();
context.Add(a)
A.ManyB
   .Select(b => b.C)
   .ForEach(c => context.Entry(c).State = EntityState.Unchanged);
context.SaveChanges();

我本以为在先前的添加之后强制 EF 将对象视为未更改应该可行,但它们似乎被忽略了。

我如何说服 EF 保存我的 C 实例一次?请注意,我不能简单地取消其中一个 B.C,因为这样就不会插入其中一个关系。我不关心在一次提交中执行此操作。什么都管用。

最佳答案

使用对象和等于运算符时存在一个问题:当在哈希表或字典键中使用对象时,覆盖 GetHashCode 方法非常重要。

EF 使用字典作为内部上下文。

尝试为您的类覆盖 GetHashCode,并且您必须确保为相同的实例对象返回相同的结果。

编辑:

EF 使用带有多个字典的内部 ObjectStateManager:AddedEntityStore、ModifiedEntityStore、DeletedEntityStore、UnchangedEntityStore (Dictionary<'EntityKey, EntityEntry>)。 当 EF 在“SaveChanges”上搜索这些字典中的实体时,使用字典的 TryGetValue 方法。 因此,为简洁起见,这是代码:

private int FindEntry(TKey key)
{
    if ((object) key == null)
    ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
    if (this.buckets != null)
    {
    int num = this.comparer.GetHashCode(key) & int.MaxValue;
    for (int index = this.buckets[num % this.buckets.Length]; index >= 0; index = this.entries[index].next)
    {
        if (this.entries[index].hashCode == num && this.comparer.Equals(this.entries[index].key, key))
        return index;
    }
    }
    return -1;
}

我们所有人都可以看到这句话: this.comparer.GetHashCode(key)

这与将 GetHashCode 与 Dictionary 和 HashTable 一起使用一样相关。 请参阅 Dino Esposito 帖子:http://software2cents.wordpress.com/2014/04/12/hash-codes-and-equality-in-the-net-framework/

关于c# - 为什么 EF 尝试使用单个或多个 SaveChanges() 插入实例两次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37119851/

相关文章:

c# - 我无法从 Controller 中的表单接收发布数据

c# - Entity Framework : Mocking with JustMock

c# - 如何处理 EntityDataSource 中的自连接?

c# - 来自同一 httpclient 实例中具有不同 url 的不同线程的两个请求

c# - EPPlus 行高大小不同

c# - 使用 EntityFramework(数据库优先)方法的 DataAnnotations

C# Linq 快速计算列表中项目的有效方法

c# - EF Core 是否可以在针对具有转换的属性的查询中调用方法?

c# - Linq c# - 加入多个条件错误

c# - Entity Framework 6 代码优先 : How to seed data with a 'circular' relationship and store-generated columns?