我正在尝试使用EF的数据注释向我的Contact
模型添加FK。我以完全相同的方式添加了两个其他FK(BillingAddressID和ShippingAddressID),它们工作得很好。我无法弄清楚为什么这个新人拒绝工作。
public class Contact
{
[Key]
public int ContactID { get; set; }
[ForeignKey("BillingAddress"), Column("DefaultBillingAddressID")]
public int? BillingAddressID { get; set; }
public virtual Address BillingAddress { get; set; }
[ForeignKey("ShippingAddress"), Column("DefaultShippingAddressID")]
public int? ShippingAddressID { get; set; }
public virtual Address ShippingAddress { get; set; }
[ForeignKey("CreditCard"), Column("DefaultCreditCardID")]
public int? CreditCardID { get; set; }
public virtual Card CreditCard { get; set; }
}
public class Address
{
[Key]
public int AddressID { get; set; }
[ForeignKey("Contact")]
public int ContactID { get; set; }
public virtual Contact Contact { get; set; }
}
public class Card
{
[Key]
public int CardID { get; set; }
[ForeignKey("Contact")]
public int ContactID { get; set; }
public virtual Contact Contact { get; set; }
}
当我尝试添加信用卡FK时,我收到以下错误:
在模型生成期间检测到一个或多个验证错误:
Contact_CreditCard_Target :: Multiplicity在Role中无效 ' Contact_CreditCard_Target'在关系' Contact_CreditCard'。 因为Dependent Role属性不是关键属性,所以 依赖角色的多样性的上限必须是' *'。
我在其他地方没有任何Fluent API的东西修复地址上的任何内容。他们似乎只是工作而卡片没有。
答案 0 :(得分:2)
我的猜测是,这是因为EF可以看到联系人有多个地址(准确地说是其中两个),因此可以做出一些关于多重性的决定,而这些决定与卡无关。
通过关系,尝试使用流畅的API来明确它是绝对的好主意。在您的情况下,您可以尝试使用卡配置来定义它:
modelBuilder.Entity<Card>()
.HasRequired(card => card.Contact)
.WithOptional(contact => contact.CreditCard);
相当于:
modelBuilder.Entity<Contact>()
.HasOptional(contact => contact.CreditCard)
.WithRequired(card => card.Contact);
执行时没有错误,并且大部分功能正常。但是,由于它发现无法在多个联系人之间共享卡,因此它决定可以通过与之相关的联系人识别卡 - 为什么在不需要的密钥上浪费列?然后我们最终进行了一次卡片迁移,如下所示:
CreateTable(
"dbo.Cards",
c => new
{
CardID = c.Int(nullable: false),
ContactID = c.Int(nullable: false),
})
.PrimaryKey(t => t.CardID)
.ForeignKey("dbo.Contacts", t => t.CardID)
.Index(t => t.CardID);
请注意,联系人的外键是通过CardId而不是ContactId。后者最终成为无用的专栏。
但是,有一种解决方法。鉴于您已将联系人上的FK调用为DefaultCreditCardId,它表示在您的域中,可能有多个信用卡,其中一个是默认信用卡。如果您接受此,则可以将配置更改为:
modelBuilder.Entity<Card>()
.HasRequired(card => card.Contact)
.WithMany();
请注意,WithMany()
不包含任何属性名称 - 联系人无法通过模型获取所有卡片。它的作用是告诉EF它无法通过ContactId从相关联系人识别卡,因为可能有多张卡。
生成的迁移看起来像这样,无论如何都是你的初始要求(我已经包含了Contact,表明它已按预期生成):
CreateTable(
"dbo.Contacts",
c => new
{
ContactID = c.Int(nullable: false, identity: true),
DefaultBillingAddressID = c.Int(),
DefaultShippingAddressID = c.Int(),
DefaultCreditCardID = c.Int(),
})
.PrimaryKey(t => t.ContactID)
.ForeignKey("dbo.Addresses", t => t.DefaultBillingAddressID)
.ForeignKey("dbo.Cards", t => t.DefaultCreditCardID)
.ForeignKey("dbo.Addresses", t => t.DefaultShippingAddressID)
.Index(t => t.DefaultBillingAddressID)
.Index(t => t.DefaultShippingAddressID)
.Index(t => t.DefaultCreditCardID);
CreateTable(
"dbo.Cards",
c => new
{
CardID = c.Int(nullable: false, identity: true),
ContactID = c.Int(nullable: false),
})
.PrimaryKey(t => t.CardID)
.ForeignKey("dbo.Contacts", t => t.ContactID, cascadeDelete: true)
.Index(t => t.ContactID);
从创建Contact
和Card
的代码的角度来看,在为联系人创建卡片时,需要明确设置Contact.DefaultCreditCardId
或Contact.CreditCard
属性它们不会自动设置。