将相同已断开连接的实体的不同实例插入到实体框架中

时间:2014-01-02 14:18:11

标签: c# entity-framework asp.net-mvc-4 oracle10g entity-framework-5

在我的MVC4项目中,我试图通过使用EF5将我从excel工作表填充的一些数据插入数据库(使用12c ODAC的Oracle 10g DB)。

故事:

首先,我从excel读取数据,然后将它们转换为实体。但是,excel数据没有主键(ID)列(我没有控制超级EXCEL数据)。因此,对于excel中的每一行,我首先搜索DB以获得匹配。如果匹配,我将使用DbContext获取匹配的实体。在这种情况下,我的实例化类/实体已经填充了ID属性。

另一方面,如果DB中没有匹配,我将实例化一个没有ID信息的新类实体类型。如果实体存在于excel工作表的多行中,则我的最终List将具有同一实体的多个实例,每个实例具有ID = 0.

填充数据后,我将我的实体逐个添加到我的DbContext中,并调用上下文的SaveChanges()方法。然后,当我检查数据库时,我看到同一个类的不同实例获得不同的ID,但这不是我想要的。

我理解为什么会发生这种情况,因为如果没有设置PK,DbContext就无法关联类的不同实例。所有实体的EntityState都变为已添加:(

我的问题是:

“有没有办法告诉实体框架,如果”实体的所有属性彼此相等&&未设置PK / ID“在插入数据库时​​将这些实体视为相同的实体?”

简化为:

在下面的代码中执行MyMethod()后,我只想在我的数据库表中创建一行数据:

// I implemented IEquatable to see if it works for EF (I heard it works in NHibernate) but unfortunately not working.
public class MyEntity(): IEquatable<MyEntity>
{
    // This is an autoincrementing PK in DB
    public int ID { get; set; }
    public string Name { get; set; }

    public bool Equals(MyEntity other)
    {
        if (other == null) return false;
        if (ReferenceEquals(this, other)) return true;

        return Equals(this.ID, other.ID) && Equals(this.Name, other.Name);
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as MyEntity);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            var result = this.ID.GetHashCode();
            result = (result * 397) ^ (this.Name!= null ? this.Name.GetHashCode() : 0);
            return result;
        }
    }
}

public void MyMethod()
{
    DbContext db = new DbContext();

    db.MyEntity.Add(new MyEntity { Name = "Foo" }) // ID=0 initially.
    db.MyEntity.Add(new MyEntity { Name = "Foo" }) // ID=0 initially.

    // When I check, the Entities in ChangeTracker are Equal!
    // This is equal to 1.
    int distinctNewEntryCount = db.ChangeTracker.Entries<MyEntity>().Select(e => e.Entity).Distinct().Count();

    // This is equal to 2.
    // But I want it to be 1 (1 Added, 1 Unchanged or only 1 Added).
    int newEntryCount = db.ChangeTracker.Entries<MyEntity>().Count(e => e.State == System.Data.EntityState.Added);

    db.SaveChanges();
}

顺便说一下,我使用的是Oracle DB,在我的EDMX文件中,我将autoincrement PK的“StoreGeneratedPattern”属性设置为“Identity”,并通过使用调用sequence.nextval()之前的insert触发器为插入的实体分配ID值。它们。

1 个答案:

答案 0 :(得分:0)

DbSet.Add返回添加到DbSet的实体,也许它返回的是与传入的实例不同的实例。此外,SaveChanges返回什么?它应该返回添加,更新和删除的对象数。它是否与您尝试插入或更新的对象数相匹配?

“如果实体存在于excel工作表的多行中,那么我的最终List将具有同一实体的多个实例,每个实例的ID = 0。”

这也可能是一个问题。您说重复/共享行将获得ID为0的唯一实体实例。它们应该使用相同的实例。