使用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可能有LoyaltyUserDetailLoyaltyUserDetail必须有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:11:0..1关系。 后者是你正在寻找的东西(“一到零”)。

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

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

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

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

PersonPhoto实体有一个名为PhotoOf的导航属性,指向Person类型。 Person类型具有名为Photo的导航属性,指向PersonPhoto类型。

在两个相关的类中,您使用每个类型的主键,而不是外键。 即,您不会使用LoyaltyUserDetailIdPIIUserId属性。 相反,关系取决于两种类型的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,一对一(或一对零/一)关系是首先在代码中配置的最令人困惑的关系之一,因此您并不孤单! :)


就像LoyaltyUserDetailPIIUser之间有一对多的关系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