使用Entity Framework Fluent API进行一对一的可选关系
我们希望使用实体框架代码优先使用一对一的可选关系。 我们有两个实体。
public class PIIUser
{
public int Id { get; set; }
public int? LoyaltyUserDetailId { get; set; }
public LoyaltyUserDetail LoyaltyUserDetail { get; set; }
}
public class LoyaltyUserDetail
{
public int Id { get; set; }
public double? AvailablePoints { get; set; }
public int PIIUserId { get; set; }
public PIIUser PIIUser { get; set; }
}
PIIUser
可能有LoyaltyUserDetail
但LoyaltyUserDetail
必须有PIIUser
。 我们尝试了这些流利的方法。
modelBuilder.Entity<PIIUser>()
.HasOptional(t => t.LoyaltyUserDetail)
.WithOptionalPrincipal(t => t.PIIUser)
.WillCascadeOnDelete(true);
此方法不会在PIIUsers表中创建LoyaltyUserDetailId外键。
之后,我们尝试了下面的代码。
modelBuilder.Entity<LoyaltyUserDetail>()
.HasRequired(t => t.PIIUser)
.WithRequiredDependent(t => t.LoyaltyUserDetail);
但是这次EF没有在这两个表中创建任何外键。
你对这个问题有什么想法吗? 我们如何使用实体框架流利的API创建一对一的可选关系?
EF Code First支持1:1
和1:0..1
关系。 后者是你正在寻找的东西(“一到零”)。
你的流利尝试在两种情况下都要求两种情况,另一种情况是两种情况都是可选的。
你需要的是一端是可选的,另一端是需要的。
下面是一个编程EF代码优先书的例子
modelBuilder.Entity<PersonPhoto>()
.HasRequired(p => p.PhotoOf)
.WithOptional(p => p.Photo);
PersonPhoto
实体有一个名为PhotoOf
的导航属性,指向Person
类型。 Person
类型具有名为Photo
的导航属性,指向PersonPhoto
类型。
在两个相关的类中,您使用每个类型的主键,而不是外键。 即,您不会使用LoyaltyUserDetailId
或PIIUserId
属性。 相反,关系取决于两种类型的Id
字段。
如果您使用上述流畅的API,则不需要指定LoyaltyUser.Id
作为外键,EF会将其计算出来。
所以如果没有你的代码来测试自己(我讨厌从头开始做这个)......我会把它翻译成你的代码
public class PIIUser
{
public int Id { get; set; }
public LoyaltyUserDetail LoyaltyUserDetail { get; set; }
}
public class LoyaltyUserDetail
{
public int Id { get; set; }
public double? AvailablePoints { get; set; }
public PIIUser PIIUser { get; set; }
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<LoyaltyUserDetail>()
.HasRequired(lu => lu.PIIUser )
.WithOptional(pi => pi.LoyaltyUserDetail );
}
这就是说LoyaltyUserDetails PIIUser
属性是必需的,PIIUser的LoyaltyUserDetail
属性是可选的。
你可以从另一端开始:
modelBuilder.Entity<PIIUser>()
.HasOptional(pi => pi.LoyaltyUserDetail)
.WithRequired(lu => lu.PIIUser);
现在说PIIUser的LoyaltyUserDetail
属性是可选的,LoyaltyUser的PIIUser
属性是必需的。
你总是必须使用HAS / WITH模式。
HTH和FWIW,一对一(或一对零/一)关系是首先在代码中配置的最令人困惑的关系之一,因此您并不孤单! :)
就像LoyaltyUserDetail
和PIIUser
之间有一对多的关系LoyaltyUserDetail
,所以你的映射应该是
modelBuilder.Entity<LoyaltyUserDetail>()
.HasRequired(m => m.PIIUser )
.WithMany()
.HasForeignKey(c => c.LoyaltyUserDetailId);
英孚应该创建你需要的所有外键,只是不关心WithMany!
你的代码有几个错误。
1:1关系是: PK <-PK ,其中一个PK侧也是FK,或PK <-FK + UC ,其中FK侧是非PK并且具有UC。 您的代码显示您有FK <-FK ,因为您将双方定义为具有FK,但这是错误的。 我PIIUser
是PK方面, LoyaltyUserDetail
是FK方面。 这意味着PIIUser
没有FK字段,但是LoyaltyUserDetail
的确。
如果1:1关系是可选的,则FK端必须至少有一个可为空的字段。
上面的pswg确实回答了你的问题,但是他/她也在PIIUser中定义了一个FK,这当然是错误的,如上所述。 因此,在界定为空的FK场LoyaltyUserDetail
,在定义属性LoyaltyUserDetail
以纪念它的FK领域,但不指定FK场PIIUser
。
你会得到你在pswg的帖子下面描述的例外,因为没有任何一方是PK方(原则结尾)。
EF在1:1方面并不是很好,因为它无法处理独特的约束。 我不是Code的专家,所以我不知道它是否能够创建UC。
(编辑)btw: 1:1 B(FK)表示在B的目标指向A的PK时,只有1个FK约束创建,而不是2。
链接地址: http://www.djcxy.com/p/37475.html上一篇: One to one optional relationship using Entity Framework Fluent API
下一篇: Add foreign keys relationship to Entity Framework Database first