如何在没有违反PRIMARY KEY约束的情况下插入带有循环引用的EntityFramework

时间:2017-01-27 19:14:20

标签: c# entity-framework wcf

  

错误:违反PRIMARY KEY约束' PK_dbo.CompanyDtoes'。   无法在对象' dbo.CompanyDtoes'中插入重复键。该   重复键值为(b20a140d-440b-4a41-b2c3-6763fa752246)。该   声明已被终止。

PersonDto

public class PersonDto : PartnerDto, IPartner
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime BirthDate { get; set; }
    public string BirthPlace { get; set; }
    public string MothersName { get; set; }
    public string TaxId { get; set; }
    public List<CompanyDto> OwnedCompanies { get; set; }

    /// <summary>
    /// Partner címe(i)
    /// </summary>
    public List<PersonAddressDto> Addresses { get; set; }

    public PersonDto()
    {
        OwnedCompanies = new List<CompanyDto>();
        Addresses = new List<PersonAddressDto>();
    }
}

CompanyDto

public class CompanyDto : PartnerDto, IPartner
{
    public string TaxNumber { get; set; }
    public int CompanyValue { get; set; }
    public List<PersonDto> Owners { get; set; }

    /// <summary>
    /// Partner címe(i)
    /// </summary>
    public List<CompanyAddressDto> Addresses { get; set; }

    public CompanyDto()
    {
        Owners = new List<PersonDto>();
        Addresses = new List<CompanyAddressDto>();
    }
}

我的DBContext:

public class PartnerDBContext : DbContext
{
    public DbSet<PersonDto> Persons { get; set; }

    public DbSet<CompanyDto> Companies { get; set; }

    public DbSet<AddressDto> Addresses { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<PersonDto>()
            .HasKey(k => k.PartnerId);

        modelBuilder.Entity<CompanyDto>()
            .HasKey(k => k.PartnerId);

        modelBuilder.Entity<AddressDto>()
            .HasKey(k => k.ID);
    }
}

我尝试插入一个新人,其中包含已存在公司的一些参考资料:

public bool InsertPerson(PersonDto personToInsert)
{
    try
    {
        using (var db = new PartnerDBContext())
        {
            db.Persons.Add(personToInsert);
            db.SaveChanges();
        }
    }
    catch (Exception ex)
    {
        return false;
    }

    return true;
}

我的问题是,我无法插入它,因为它写了违反CompanyDto的主键。我知道它已经存在,我不想添加新的,但我应该如何添加它?我在从WWP调用的WCF服务中使用它。遗憾的是,无法使用UWP中的DataAnnonations(这是一个bug),所以我使用了ModelBuilder ......

2 个答案:

答案 0 :(得分:0)

    public bool InsertPerson(PersonDto personToInsert)
    {
        try
        {
            using (var db = new PartnerDBContext())
            {
                var companies = personToInsert.OwnedCompanies;

                personToInsert.OwnedCompanies = new List<CompanyDto>();

                foreach (var company in companies)
                {
                    var companyInDb = db.Companies.Find(company.PartnerId);
                    personToInsert.OwnedCompanies.Add(companyInDb);
                }

                db.Persons.Add(personToInsert);
                db.SaveChanges();
            }
        }
        catch (Exception ex)
        {
            return false;
        }

        return true;
    }

我找到了解决方案,如果我从数据库中获取公司,它可以保存所有内容。

答案 1 :(得分:0)

问题在于,当您将人员实体添加到上下文时,它还会添加相关实体并将其标记为Added(即新的)。 SaveChanges()反过来尝试将它们插入数据库中,您将获得重复的PK异常。

您发布的解决方案有效,但涉及检索相关对象的不必要的数据库跳转。由于您知道它们存在,您可以通过简单地将它们预先附加到上下文来避免这种情况,这会将它们标记为Unchanged(即存在)。然后SaveChanges将仅插入人员记录和链接。

using (var db = new PartnerDBContext())
{
    foreach (var company in personToInsert.OwnedCompanies)
        db.Companies.Attach(company);
    db.Persons.Add(personToInsert);
    db.SaveChanges();
}

或者,您可以在将此人添加到上下文后将其标记为Unchanged

using (var db = new PartnerDBContext())
{
    db.Persons.Add(personToInsert);
    foreach (var company in personToInsert.OwnedCompanies)
        db.Entry(company).State = EntityState.Unchanged;
    db.SaveChanges();
}

在我的测试中(最新的EF6.1.3,与发布的样本中一样短暂的新DbContext)这两种方法都有效。