添加到多对多关系表会在db中生成重复值

时间:2015-04-15 20:33:28

标签: c# asp.net-mvc database entity-framework

我有三个表zRequest,zFacility和一个表,用于两者之间的多对多关系,只有每个表的id。我的目标是添加一个包含许多设施的请求。但每当我使用某些工具添加新请求时,它会将选定的工具添加到zFacility并添加到关系表中。

这是控制器中的相关代码:

foreach (var facility in Facilities)
{
    var facName = facility.Replace(".", " ");
    var facQry = from fac in db.zFacilities where fac.FacilityName == facName select fac;
    var facList = facQry.ToList();
    var item = new zFacility();
    item.FacilityId = facList.FirstOrDefault().FacilityId;
    item.FacilityName = facList.FirstOrDefault().FacilityName;
    //db.zFacility.Attach(item);
    zrequest.zFacility.Add(item);
}
zrequestRepository.InsertOrUpdate(zrequest);
zrequestRepository.Save();

我做了一些研究并尝试通过注释行将每个工具附加到数据库但是这给了我另一个错误,因为同一类型的另一个实体已经具有相同的主键值

这是来自zRequestRepository的代码:

public void InsertOrUpdate(zRequest zrequest)
    {
        if (zrequest.RequestId == default(int)) {
            // New entity
            context.zRequests.Add(zrequest);
        } else {
            // Existing entity
            context.Entry(zrequest).State = System.Data.Entity.EntityState.Modified;
        }
    }

我该怎么做才能解决这个问题?如果我需要提供更多信息,请告诉我......

编辑,根据要求提供相关模型。 zFacility:

using System;
using System.Collections.Generic;

public partial class zFacility
{
    public zFacility()
    {
        this.zRequest = new HashSet<zRequest>();
        this.zRoom = new HashSet<zRoom>();
    }

    public short FacilityId { get; set; }
    public string FacilityName { get; set; }

    public virtual ICollection<zRequest> zRequest { get; set; }
    public virtual ICollection<zRoom> zRoom { get; set; }
}

zRequest:

using System;
using System.Collections.Generic;

public partial class zRequest
{
    public zRequest()
    {
        this.zFacility = new HashSet<zFacility>();
        this.zRoom = new HashSet<zRoom>();
    }

    public int RequestId { get; set; }
    public string ModCode { get; set; }
    public short StatusId { get; set; }
    public int WeekId { get; set; }
    public short DayId { get; set; }
    public short PeriodId { get; set; }
    public short SessionLength { get; set; }
    public short Semester { get; set; }
    public short RoundNo { get; set; }
    public string SpecialRequirement { get; set; }
    public short UserId { get; set; }

    public virtual zDay zDay { get; set; }
    public virtual zPeriod zPeriod { get; set; }
    public virtual zRound zRound { get; set; }
    public virtual zStatus zStatus { get; set; }
    public virtual zWeek zWeek { get; set; }
    public virtual ICollection<zFacility> zFacility { get; set; }
    public virtual ICollection<zRoom> zRoom { get; set; }
    public virtual zUser zUser { get; set; }
}

这些都是通过数据库优先生成的。

3 个答案:

答案 0 :(得分:1)

默认情况下,EF假定所选设施( zFacility)是新的,并将它们插入数据库。

为避免这种情况,您需要将状态更改为Unchanged zFacility

像这样的东西

public void InsertOrUpdate(zRequest zrequest)
    {
        if (zrequest.RequestId == default(int)) {
        context.zFacility.Attach(zrequest); // state Unchanged for zFacility  
        // New entity
       context.zRequests.Add(zrequest);
            } else {
            // Existing entity
            context.Entry(zrequest).State = System.Data.Entity.EntityState.Modified;
        }
    }

答案 1 :(得分:0)

您需要做的是从DB中选择zFactories对象,而不是为每个对象创建新对象,因为这会让EF认为您想要创建全新的记录。

所以: 选择zFactories 将它们添加到zRequest.zFacility(如果它们尚未存在) 保存

答案 2 :(得分:0)

由于您的代码中存在一些漏洞,因此有点难以回答这个问题。根据用法,我假设Facilities是一个可枚举的字符串,并根据您的帖子数据中的选定项目创建。

我不确定您为什么要创建新的zFacility,而不是使用您已经从数据库中提取的那个。{1}}。按照您的方式进行,如果没有匹配工具,您还会引入空引用异常的可能性。

无论如何,我会改变你所拥有的代码:

// This is so you can run a single minimal query to select
// all the facilities you'll be working with
var facNames = Facilities.Select(m => m.Replace(".", " "));
var facList = db.zFacilities.Where(m => facNames.Contains(m.FacilityName)).ToList();

// Now add all facilities not currently attached
facList.Where(m => !zrequest.zFacility.Contains(m)).ToList()
    .ForEach(m => zrequest.zFacility.Add(m));

您可能还需要删除已取消选择的项目。最简单的方法是反向执行最后一段代码:

zrequest.zFacility.Where(m => !facList.Contains(m)).ToList()
    .ForEach(m => zrequest.zFacility.Remove(m));

修改

实际上,删除取消选择的项目的更简洁方法是:

zrequest.zFacility.RemoveAll(m => !factList.Contains(m));