Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将相同断开连接实体的不同实例插入实体框架_C#_Entity Framework_Asp.net Mvc 4_Oracle10g_Entity Framework 5 - Fatal编程技术网

C# 将相同断开连接实体的不同实例插入实体框架

C# 将相同断开连接实体的不同实例插入实体框架,c#,entity-framework,asp.net-mvc-4,oracle10g,entity-framework-5,C#,Entity Framework,Asp.net Mvc 4,Oracle10g,Entity Framework 5,在我的MVC4项目中,我尝试将一些数据(从excel工作表填充)插入数据库Oracle 10g DB,使用12c ODAC和EF5 故事: 首先,我从excel中读取数据,然后将其转换为实体。但是excel数据没有主键ID列,我无法控制excel数据。因此,对于excel中的每一行,我首先在DB中搜索匹配项。如果存在匹配,我将使用DbContext获取匹配的实体。在这种情况下,实例化的类/实体已填充ID属性 另一方面,如果数据库中没有匹配项,我将实例化一个没有ID信息的实体类型的新类。如果实体存

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

故事:

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

另一方面,如果数据库中没有匹配项,我将实例化一个没有ID信息的实体类型的新类。如果实体存在于excel工作表的多行中,则我的最终列表将包含同一实体的多个实例,每个实例的ID均为0

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

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

我的问题是:

是否有一种方法可以告诉Entity Framework,如果一个实体的所有属性都彼此相等&&未设置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属性设置为标识,并通过使用在插入前调用sequence.nextval的触发器将ID值分配给插入的实体。

DbSet.Add返回添加到DbSet的实体,可能它返回的实例与传入的实例不同。另外,SaveChanges返回什么?它应该返回添加、更新和删除的对象的列表。它是否与您尝试插入或更新的对象的类型匹配

如果实体存在于excel工作表的多行中,则我的最终列表将包含同一实体的多个实例,每个实例的ID均为0


这可能也是一个问题。您的意思是,重复/共享行将获得其自己的ID为0的唯一实体实例。他们应该使用相同的实例。

我已经在做你所说的了。在常规列表中收集新实体,并针对每个新数据将数据与这些列表进行比较,每个excel行包含多个实体的信息,如果发现匹配项,则不在DbContext中再次添加实例。然而,我不喜欢这个解决方案,并试图找到一个简单的解决方案,EF处理这个逻辑。如果我找不到更优雅的方法,我将继续使用我的解决方案。