一对一使用entity framework代码的可选关系

我们希望使用entity framework代码优先使用一对一的可选关系。 我们有两个实体。

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必须具有PII用户。 我们尝试了这些stream利的方法。

 modelBuilder.Entity<PIIUser>() .HasOptional(t => t.LoyaltyUserDetail).WithOptionalPrincipal(t => t.PIIUser) .WillCascadeOnDelete(true); 

这种方法没有在PIIUsers表中创buildLoyaltyUserDetailId外键。

之后,我们尝试了下面的代码。

 modelBuilder.Entity<LoyaltyUserDetail>().HasRequired(t => t.PIIUser).WithRequiredDependent(t => t.LoyaltyUserDetail); 

但是这次EF没有在这两个表中创build任何外键。

你对这个问题有什么想法吗? 我们如何使用entity framework代码首先创build一对一的可选关系?

EF Code First支持1:11:0..1关系。 后者是你正在寻找的(“一到零”)。

你的stream利的尝试在两种情况下都要求两种情况,另一种情况是两种情况都是可选的。

你需要的是一端是可选的 ,另一端是需要的。

这是一个编程EF代码优先书的例子

 modelBuilder.Entity<PersonPhoto>() .HasRequired(p => p.PhotoOf) .WithOptional(p => p.Photo); 

PersonPhoto实体有一个名为PhotoOf的导航属性,指向一个Persontypes。 Persontypes有一个名为Photo的导航属性,指向PersonPhototypes。

在两个相关的类中,您使用每个types的主键 ,而不是外键 。 即,您将不会使用LoyaltyUserDetailIdPIIUserId属性。 相反,关系取决于两种types的Id字段。

如果你使用上面的stream畅的API,你不需要指定LoyaltyUser.Id作为外键,EF将会把它弄清楚。

所以没有你的代码来testing自己(我讨厌从头开始)…我会把它翻译成你的代码

 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,一对一(或一对零/一)关系是首先在代码中configuration最混乱的关系之一,所以你并不孤单! 🙂

我们你最初的代码,

就像LoyaltyUserDetailPIIUser之间有一对多的关系LoyaltyUserDetail ,那么你的映射应该是

 modelBuilder.Entity<LoyaltyUserDetail>() .HasRequired(m => m.PIIUser ) .WithMany() .HasForeignKey(c => c.LoyaltyUserDetailId); 

EF应该创build你需要的所有外键,只是不关心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端必须至less有1个可为空的字段。

上面的pswg确实回答了你的问题,但却犯了一个错误,他/她还在PIIUser中定义了一个FK,这当然是错误的,正如我上面所描述的那样。 因此,定义LoyaltyUserDetail的可空FK字段,在LoyaltyUserDetail中定义属性以将其标记为FK字段,但是不在PIIUser指定FK字段。

你会得到你在pswg的post下面描述的例外,因为没有任何一方是PK方(原则结束)。

EF在1:1方面并不是很好,因为它无法处理独特的限制。 我不是Code的第一个专家,所以我不知道它是否能够创build一个UC。

(编辑)btw: 1:1 B(FK)意味着只有1个FK约束创build,B指向A的PK的目标不是2。

尝试添加LoyaltyUserDetail属性的ForeignKey属性:

 public class PIIUser { ... public int? LoyaltyUserDetailId { get; set; } [ForeignKey("LoyaltyUserDetailId")] public LoyaltyUserDetail LoyaltyUserDetail { get; set; } ... } 

PIIUser属性:

 public class LoyaltyUserDetail { ... public int PIIUserId { get; set; } [ForeignKey("PIIUserId")] public PIIUser PIIUser { get; set; } ... } 
 public class User { public int Id { get; set; } public int? LoyaltyUserId { get; set; } public virtual LoyaltyUser LoyaltyUser { get; set; } } public class LoyaltyUser { public int Id { get; set; } public virtual User MainUser { get; set; } } modelBuilder.Entity<User>() .HasOptional(x => x.LoyaltyUser) .WithOptionalDependent(c => c.MainUser) .WillCascadeOnDelete(false); 

这将解决REFERENCEFOREIGN KEYS上的问题

更新删除logging时