Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.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# EF将重复记录添加到查找/引用表中_C#_Sql Server_Entity Framework_Ef Code First - Fatal编程技术网

C# EF将重复记录添加到查找/引用表中

C# EF将重复记录添加到查找/引用表中,c#,sql-server,entity-framework,ef-code-first,C#,Sql Server,Entity Framework,Ef Code First,我有三张桌子, 1.AttributeType(列:AttributeId(PK)、AttributeName、…) 2.位置(列:locationId(PK)、LocationName等) 3.LocationAttributeType(列:locationId(FK)、AttributeId(FK)) 每当我试图从GUI插入新的位置记录及其属性类型时,它都应该为表-location和LocationAttributeType创建新记录。但EF也试图在表-AttributeType中添加新记录

我有三张桌子, 1.AttributeType(列:AttributeId(PK)、AttributeName、…) 2.位置(列:locationId(PK)、LocationName等) 3.LocationAttributeType(列:locationId(FK)、AttributeId(FK))

每当我试图从GUI插入新的位置记录及其属性类型时,它都应该为表-locationLocationAttributeType创建新记录。但EF也试图在表-AttributeType中添加新记录,该表仅用作参考表,不应在其中添加新的/重复的记录。我怎样才能防止呢

这是我的密码

GUI发送的模型是

public class LocationDataModel
{
    [DataMember]
    public int Id { get; set; }

    [DataMember]
    public string Code { get; set; }

    [DataMember]
    public List<AttributeTypeDataModel> AssignedAttributes = new List<AttributeTypeDataModel>();
}
public class AttributeTypeDataModel
{
    protected AttributeTypeDataModel() {}

    public AttributeTypeDataModel(int id) { this.Id = id; }

    public AttributeTypeDataModel(int id, string name)
        : this(id)
    {
        this.Name = name;
    }

    [DataMember]
    public int Id { get; set; }

    [DataMember]
    public string Name { get; set; }

    [DataMember]
    public virtual ICollection<LocationDataModel> Locations { get; set; }
  }
公共类LocationDataModel
{
[数据成员]
公共int Id{get;set;}
[数据成员]
公共字符串代码{get;set;}
[数据成员]
public List AssignedAttributes=新列表();
}
公共类attributeTypedAtModel
{
受保护的AttributeTypedAtModel(){}
public attributeTypedAtModel(int-id){this.id=id;}
public attributeTypedAtModel(int-id,字符串名)
:此(id)
{
this.Name=Name;
}
[数据成员]
公共int Id{get;set;}
[数据成员]
公共字符串名称{get;set;}
[数据成员]
公共虚拟ICollection位置{get;set;}
}
EF创建的实体包括:

public partial class Location
{
    public Location()
    {
        this.AttributeTypes = new List<AttributeType>();
    }

    public Location(int campusId, string code)
        : this()
    {
        CampusId = campusId; Code = code;
    }


    public int Id { get; set; }
    public int CampusId { get; set; }
    public string Code { get; set; }
    public virtual ICollection<AttributeType> AttributeTypes { get; set; }
公共部分类位置
{
公共场所()
{
this.attributeType=新列表();
}
公共位置(int-campusId,字符串代码)
:此()
{
CampusId=CampusId;Code=Code;
}
公共int Id{get;set;}
公共int CampusId{get;set;}
公共字符串代码{get;set;}
公共虚拟ICollection属性类型{get;set;}
}

公共部分类AttributeType
{
公共属性类型()
{
this.Locations=新列表();
}
public int AttributeTypeId{get;set;}
公共字符串AttributeTypeName{get;set;}
公共虚拟ICollection位置{get;set;}
}
我有以下代码将这些新位置添加到数据库中

     private IEnumerable<TEntity> AddEntities<TModel, TEntity, TIdentityType>
     (IEnumerable<TModel> models, Func<TModel, TIdentityType> primaryKey, 
        IGenericRepository<TEntity, TIdentityType> repository)
        {
        var results = new List<TEntity>();

        foreach (var model in models)
        {
            var merged = _mapper.Map<TModel, TEntity>(model);
            var entity = repository.Upsert(merged);
            results.Add(entity);
        }
        repository.Save();
        return results.AsEnumerable();
    }
私有IEnumerable加法
(IEnumerable models,Func primaryKey,
IGenericRepository存储库)
{
var results=新列表();
foreach(模型中的var模型)
{
var merged=\u mapper.Map(模型);
var entity=repository.Upsert(合并);
结果:增加(实体);
}
Save();
返回结果;
}
我使用以下通用存储库来执行与实体相关的操作

public TEntity Upsert(TEntity entity)
    {
        if (Equals(PrimaryKey.Invoke(entity), default(TId)))
        {
            // New entity
            return Context.Set<TEntity>().Add(entity);
        }
        else
        {
            // Existing entity
            Context.Entry(entity).State = EntityState.Modified;
            return entity;
        }
    }

   public void Save()
    {
        Context.SaveChanges();
    }
public tenty Upsert(tenty实体)
{
if(等于(PrimaryKey.Invoke(entity),默认值(TId)))
{
//新实体
返回Context.Set().Add(实体);
}
其他的
{
//现有实体
Context.Entry(entity.State=EntityState.Modified;
返回实体;
}
}
公共作废保存()
{
SaveChanges();
}

我在这里做错了什么?

在您的
Upsert
else
语句中,您应该添加

context.TEntity.Attach(entity);
DbSet.Add()。您需要向EF指出“引用”实体实际上已经存在。有两种简单的方法可以做到这一点:


  • 不要将导航属性设置为对象。相反,只需将相应的外键属性设置为正确的值

  • 您需要确保不会将同一实体的多个实例加载到对象上下文中。创建上下文后,将
    AttributeType
    实体的完整列表加载到上下文中,并创建一个
    字典来存储它们。如果要将属性添加到
    位置
    中,请从字典中检索相应的属性。调用
    SaveChanges()
    之前,请遍历字典,并将每个
    AttributeType
    标记为未更改。大概是这样的:

        using (MyContext c = new MyContext())
        {
            c.AttributeTypes.Add(new AttributeType { AttributeTypeName = "Fish", AttributeTypeId = 1 });
            c.AttributeTypes.Add(new AttributeType { AttributeTypeName = "Face", AttributeTypeId = 2 });
            c.SaveChanges();
        }
    
        using (MyContext c = new MyContext())
        {
            Dictionary<int, AttributeType> dictionary = new Dictionary<int, AttributeType>();
    
            foreach (var t in c.AttributeTypes)
            {
                dictionary[t.AttributeTypeId] = t;
            }
    
            Location l1 = new Location(1, "Location1") { AttributeTypes = { dictionary[1], dictionary[2] } };
            Location l2 = new Location(2, "Location2") { AttributeTypes = { dictionary[1] } };
    
            // Because the LocationType is already attached to the context, it doesn't get re-added.
            c.Locations.Add(l1);
            c.Locations.Add(l2);
    
            c.SaveChanges();
        }
    
    使用(MyContext c=new MyContext())
    {
    c、 Add(新的AttributeType{AttributeTypeName=“Fish”,AttributeTypeId=1});
    c、 Add(新的AttributeType{AttributeTypeName=“Face”,AttributeTypeId=2});
    c、 保存更改();
    }
    使用(MyContext c=new MyContext())
    {
    字典=新字典();
    foreach(c.attributeType中的变量t)
    {
    字典[t.AttributeTypeId]=t;
    }
    位置l1=新位置(1,“位置1”){attributeType={dictionary[1],dictionary[2]};
    位置l2=新位置(2,“位置2”){attributeType={dictionary[1]};
    //由于LocationType已附加到上下文,因此不会重新添加它。
    c、 位置。添加(l1);
    c、 位置。添加(l2);
    c、 保存更改();
    }
    
在这种特定情况下,您使用的是一种多对多关系,EF自动处理中间表。这意味着您实际上没有在模型中公开FK属性,并且我上面的第一个建议将不起作用

因此,您要么需要使用第二个建议,这仍然应该有效,要么需要放弃对中间表的自动处理,而是为它创建一个实体。这将允许您应用第一个建议。您将拥有以下模型:

public partial class Location
{
    public Location()
    {
        this.AttributeTypes = new List<LocationAttribute>();
    }

    public Location(int campusId, string code)
        : this()
    {
        CampusId = campusId; Code = code;
    }

    public int Id { get; set; }
    public int CampusId { get; set; }
    public string Code { get; set; }
    public virtual ICollection<LocationAttribute> AttributeTypes { get; set; }
}

public partial class LocationAttribute
{
    [ForeignKey("LocationId")]
    public Location Location { get; set; }
    public int LocationId { get; set; }

    public int AttributeTypeId { get; set; }
}

public partial class AttributeType
{
    public int AttributeTypeId { get; set; }
    public string AttributeTypeName { get; set; }
}
公共部分类位置
{
公共场所()
{
this.attributeType=新列表();
}
公共位置(int-campusId,字符串代码)
:此()
{
CampusId=CampusId;Code=Code;
}
公共int Id{get;set;}
公共int CampusId{get;set;}
公共字符串代码{get;set;}
公共虚拟ICollection属性IP
public partial class Location
{
    public Location()
    {
        this.AttributeTypes = new List<LocationAttribute>();
    }

    public Location(int campusId, string code)
        : this()
    {
        CampusId = campusId; Code = code;
    }

    public int Id { get; set; }
    public int CampusId { get; set; }
    public string Code { get; set; }
    public virtual ICollection<LocationAttribute> AttributeTypes { get; set; }
}

public partial class LocationAttribute
{
    [ForeignKey("LocationId")]
    public Location Location { get; set; }
    public int LocationId { get; set; }

    public int AttributeTypeId { get; set; }
}

public partial class AttributeType
{
    public int AttributeTypeId { get; set; }
    public string AttributeTypeName { get; set; }
}
private IEnumerable<int> AddLocationEntities(IEnumerable<LocationDataModel> locations)
    {
        var results = new List<int>();
        foreach (LocationDataModel l in locations)
        {
            var entity = _mapper.Map<LocationDataModel, Location>(l);//you can map manually also
            var AttributeCode = l.AssignedAttributes.FirstOrDefault().AttributeTypeId;
            using (MyContext c = new MyContext())
            {
                var attr = c.AttributeTypes.Where(a => a.Id == AttributeTypeId ).ToList();
                entity.AttributeTypes = attr;
                c.Locations.Add(entity);
                c.SaveChanges();
                var locid = entity.Id;
                results.Add(locid);
            }

        }
      return results;
    }