我正在尝试创建2个表。一个用于商店,一个用于收银机。收银机有复合键:Id + ShopId
这是一个模型:
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 :(得分: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
时,第二次执行种子时可能会出现重复。
答案 1 :(得分: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个CashRegister对象。两个商店各两个。当ShopId设置为主键时,则CashRegister Table不能两次使用相同的ShopId。
解决方案是为每个Shop对象插入一个CashRegister对象,或从ShopId中删除主要约束。