简体   繁体   English

实体框架代码第一个唯一索引外键引发DbUpdate异常

[英]Entity Framework Code First unique index foreign key throws DbUpdate Exception

Here's the entites and context code: 这是实体和上下文代码:

public class Family
{
    public int FamilyID { get; set; }
    public String address { get; set; }
    public virtual ICollection<Member> FamilyMembers { get; set; }
}
public class Member
{
    [Index("MemberUniqueID", IsUnique = true)]
    public int MemberID { get; set; }

    [StringLength(50)] [Index("MemberUniqueIndex", 1, IsUnique = true)]
    public String name { get; set; }
    [StringLength(50)] [Index("MemberUniqueIndex", 2, IsUnique = true)]
    public String surname { get; set; }

    public int age { get; set; }
    public int FamilyID { get; set; }
    public virtual Family Family { get; set; }
}
public class Bicycle
{
    public int BicycleID { get; set; }
    public virtual Member Owner { get; set; }
}
public class MyContext : DbContext
{
    public MyContext : base () { }
    public DbSet<Member> MemberDB { get; set; }
    public DbSet<Family> FamilyDB { get; set; }
    public DbSet<Bicycle> BicycleDB { get; set; }
}

Now, I add a few examples of each, add them and SaveChanges(); 现在,我为每个示例添加一些示例,并添加它们和SaveChanges(); . Then I try to run this code: 然后,我尝试运行以下代码:

    public void bicycle_set_FK(int IDbicycle, int IDmember)
{
       var bicycleToFind = BicycleDB.Find(IDbicycle);
       var memberToSetAsFK = MemberDB.Find(IDmember);
       bicycleToFind.Owner = memberToSetAsFK;
       SaveChanges();
}

And as a result, I get this error: 结果,我得到这个错误:

An unhandled exception of type 'System.Data.Entity.Infrastructure.DbUpdateException' occurred in EntityFramework.dll Cannot insert duplicate key row in object 'dbo.Members' with unique index 'MemberUniqueIndex'. EntityFramework.dll中发生了类型为'System.Data.Entity.Infrastructure.DbUpdateException'的未处理异常。无法在具有唯一索引'MemberUniqueIndex'的对象'dbo.Members'中插入重复的键行。 The duplicate key value is (John, Smith). 重复的键值为(John,Smith)。 The statement has been terminated. 该语句已终止。

The weird thing is, if I run that method simultaneously while adding the examples, the method works fine and sets the FK as expected. 奇怪的是,如果我在添加示例的同时运行该方法,则该方法可以正常工作并按预期设置FK。 But if I first add the examples with the first run of the code, and I try to set FKs on the second run of the code, it throws that exception. 但是,如果我首先在代码的第一次运行中添加示例,然后尝试在代码的第二次运行中设置FK,则会抛出该异常。

EDIT: 编辑:

Okay, so I've done as recommended and after reading the artice you linked I have this: 好的,所以我已经按照建议完成了,在阅读了您链接的文章后,我得到了:

[ForeignKey("MemberID")]
public int? OwnerID { get; set; }
public virtual Member MemberID { get; set; }

And the method looks like this: 该方法如下所示:

public void bicycle_set_FK(int IDbicycle, int IDmember)
{
   var bicycleToFind = BicycleDB.Find(IDbicycle);
   bicycleToFind.MemberID = null;
   bicycleToFind.OwnerID = IDmember;
   SaveChanges();
}

But this generates a new problem: 但这产生了一个新问题:

"Violation of PRIMARY KEY constraint 'PK_dbo.Members'. Cannot insert duplicate key in object 'dbo.Members'. The duplicate key value is (0).\\r\\nThe statement has been terminated." “违反了PRIMARY KEY约束'PK_dbo.Members'。无法在对象'dbo.Members'中插入重复键。重复键值为(0)。\\ r \\ n该语句已终止。“

The values I use are 1 and 3 ( bicycle_set_FK(1, 3); ). 我使用的值是1和3( bicycle_set_FK(1, 3); )。 Members contain 3 rows with IDs: 1, 2 and 3. So where does it find that zero, since it's not in the database nor do I enter it at any point in the code? 成员包含ID为1、2和3的3行。那么,该零在哪里找到,因为它不在数据库中,所以我也不能在代码的任何位置输入它。

And one more thing: the article doesn't mention how to solve that problem in a one-to-many relationship. 还有一件事:本文没有提到如何以一对多关系解决该问题。 How do I add FK between Family and Member? 如何在家庭和会员之间添加FK? Do I add some property such as public List<Member> FamilyMembersFK ? 是否添加一些属性,例如public List<Member> FamilyMembersFK

Entity framework is re-adding your Owner(Member). 实体框架正在重新添加您的Owner(成员)。 There are a couple of ways around this, but since you have the FK try this: 有两种方法可以解决此问题,但是既然您有FK,请尝试以下操作:

public class Bicycle
{
    public int BicycleID { get; set; }

    public int MemberID { get; set; }  // You can call this ownerId, but then you need to setup the relationship with annotation or fluent
    public virtual Member Owner { get; set; }
}

public void bicycle_set_FK(int IDbicycle, int IDmember)
{
   var bicycleToFind = BicycleDB.Find(IDbicycle);
   // var memberToSetAsFK = MemberDB.Find(IDmember); ** Don't need to do this since you have FK **
   bicycleToFind.MemberId = IDmember;
   SaveChanges();
}

See https://msdn.microsoft.com/en-us/magazine/dn166926.aspx?f=255&MSPPError=-2147217396 参见https://msdn.microsoft.com/zh-cn/magazine/dn166926.aspx?f=255&MSPPError=-2147217396

EDIT: First, I highly recommend you follow some convention when naming your navigation classes and keys. 编辑:首先,我强烈建议您在命名导航类和键时遵循一些约定。 You are calling your navigation class "MemberId" - that is very confusing. 您正在将导航类称为“ MemberId”-这非常令人困惑。 If you want the FK to be OwnerId, go with something like this: 如果您希望FK成为OwnerId,请执行以下操作:

public int? OwnerID { get; set; }

[ForeignKey("OwnerID")]
public virtual Member Owner { get; set; }

Second, you don't need this annotation: 其次,您不需要此注释:

//[Index("MemberUniqueID", IsUnique = true)]  **MemberID will be a identity key by default so it will have a unique index created.
public int MemberID { get; set; }

Now you can insert an existing owner like this: 现在,您可以像这样插入现有所有者:

public void bicycle_set_FK(int IDbicycle, int IDmember)
{
   var bicycleToFind = BicycleDB.Find(IDbicycle);
   bicycleToFind.OwnerID = IDmember;  // Don't worry about the nav class, just set the FK
   SaveChanges();
}

Regarding the one to many, you already have that configured with: 关于一对多,您已经配置了:

public virtual ICollection<Member> FamilyMembers { get; set; }

So to add a new member: 因此要添加一个新成员:

var newMember = new Member {
    Name = "Joe",
    Surname = "Smith",
    Age = 30,
    FamilyId = familyId
};

context.Members.Add(newMember);
SaveChanges();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM