2017-06-22 188 views
0

我正在尝试创建2个表。一个用于商店和一个用于收款机。收银机具有复合键:身份证+ ShopId添加或更新EF复合主键违规

这里是一个模式:

public class Shop 
{ 
    [Key] 
    public int Id { get; set; } 
    public string ShopName { get; set; } 
} 

public class CashRegister 
{ 
    [Key, Column(Order = 0)] 
    public int Id { get; set; } 
    public string CashRegisterName { get; set; } 

    [ForeignKey("ShopId")] 
    public Shop Shop { get; set; } 

    [Key, Column(Order = 1)] 
    public int ShopId { get; set; } 
} 

这里是移民的样子:

 CreateTable(
      "dbo.CashRegisters", 
      c => new 
       { 
        Id = c.Int(nullable: false), 
        ShopId = c.Int(nullable: false), 
        CashRegisterName = c.String(), 
       }) 
      .PrimaryKey(t => new { t.Id, t.ShopId }) 
      .ForeignKey("dbo.Shops", t => t.ShopId, cascadeDelete: true) 
      .Index(t => t.ShopId); 

     CreateTable(
      "dbo.Shops", 
      c => new 
       { 
        Id = c.Int(nullable: false, identity: true), 
        ShopName = c.String(), 
       }) 
      .PrimaryKey(t => t.Id); 

这里是抛出主键冲突异常的代码:

 var context = new Model(); 

     var shops = new List<Shop> 
     { 
      new Shop() { ShopName = "First shop" }, 
      new Shop() { ShopName = "Second shop" } 
     }; 

     context.Shops.AddOrUpdate(shops.ToArray()); 
     context.SaveChanges(); 

     var cashRegisters = new List<CashRegister>(); 

     foreach (var shop in shops) 
     { 
      cashRegisters.Add(new CashRegister() 
      { 
       CashRegisterName = "First cash register", 
       ShopId = shop.Id 
      }); 

      cashRegisters.Add(new CashRegister() 
      { 
       CashRegisterName = "Second cash register", 
       ShopId = shop.Id 
      }); 
     } 

     context.CashRegisters.AddOrUpdate(a => new { a.Id, a.ShopId }, cashRegisters.ToArray()); 
     context.SaveChanges(); 
     //primary key violation exception on line above 

现在很明显,收银机在创建时有0个Id 。 我得到的例外是:

"Violation of PRIMARY KEY constraint 'PK_dbo.CashRegisters'. Cannot insert duplicate key in object 'dbo.CashRegisters'. The duplicate key value is (0, 1).\r\nThe statement has been terminated."

我尝试添加[DatabaseGenerated(DatabaseGeneratedOption.Identity)]CashRegister.Id 后来我得到另一个异常{"Cannot insert the value NULL into column 'Id', table 'TestCompositeKeys.dbo.CashRegisters'; column does not allow nulls. INSERT fails.\r\nThe statement has been terminated."},这是奇怪的,因为Id甚至没有空。

谁能告诉我我做错了什么,或者我该如何解决这个问题?谢谢

+0

也许在你的'CashRegister'中,你需要分配'Shop'属性(对象),而不仅仅是外键。 –

+1

@JoseLuis谢谢你的评论,但它没有帮助。我添加了一条异常消息。我相信用Id(0,1)插入第一个记录,然后用Id(0,1)插入第二个记录,这导致异常。如果它不是一个复合键它会工作正常 – netaholic

+1

我想了解*为什么*你使用复合主键。通常,在极少数情况下,密钥的每个部分都将由其他现有实体确定,因此复合密钥永远不会有自动生成的组件。 – grek40

回答

2

设置CashRegister.Id自动增量应该实际上工作。

public class CashRegister 
{ 
    [Key, Column(Order = 0), DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public int Id { get; set; } 
    // ... 

要考虑的另一件事是AddOrUpdate声明。由于Id只会在实际插入时分配,因此您无法通过Id真正比较条目。相反,你可以尝试以下方法:

context.CashRegisters.AddOrUpdate(a => new { a.ShopId, a.CashRegisterName }, cashRegisters.ToArray()); 

它只会使用初始化的性能进行比较,将真正防止再插入,而与a.Id, a.ShopId执行种子第二遍的时候,你可能会得到重复。

+0

感谢您使用'AddOrUpdate'提示,您是对的 – netaholic

1

在这里,这

foreach (var shop in shops) 
     { 
      cashRegisters.Add(new CashRegister() 
      { 
       CashRegisterName = "First cash register", 
       ShopId = shop.Id 
      }); 

      cashRegisters.Add(new CashRegister() 
      { 
       CashRegisterName = "Second cash register", 
       ShopId = shop.Id 
      }); 
     } 

代码将插入4一下现金出纳机对象。两个商店都有两个。当ShopId设置为主键时,则对于CashRegister表不能有两次相同的ShopId。

解决方案是为每个Shop对象插入一个CashRegister对象或从ShopId中删除主约束。

相关问题