使用Entity Framework Fluent API的一对一可选关系

İlk*_*nur 75 c# entity-framework one-to-one ef-code-first ef-fluent-api

我们希望使用Entity Framework Code First使用一对一的可选关系.我们有两个实体.

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; }
}
Run Code Online (Sandbox Code Playgroud)

PIIUser可能有LoyaltyUserDetailLoyaltyUserDetail必须有PIIUser.我们尝试了这些流畅的方法技巧.

modelBuilder.Entity<PIIUser>()
            .HasOptional(t => t.LoyaltyUserDetail)
            .WithOptionalPrincipal(t => t.PIIUser)
            .WillCascadeOnDelete(true);
Run Code Online (Sandbox Code Playgroud)

这种方法没有LoyaltyUserDetailIdPIIUsers表中创建外键.

之后我们尝试了以下代码.

modelBuilder.Entity<LoyaltyUserDetail>()
            .HasRequired(t => t.PIIUser)
            .WithRequiredDependent(t => t.LoyaltyUserDetail);
Run Code Online (Sandbox Code Playgroud)

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

你对这个问题有什么想法吗?我们如何使用实体框架流畅的api创建一对一的可选关系?

Jul*_*man 96

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

你的流利尝试是在一个案例的两端需要,另一个在两端都是可选的.

您需要的是一端可选,另一端需要.

这是编程EF代码第一本书中的一个例子

modelBuilder.Entity<PersonPhoto>()
.HasRequired(p => p.PhotoOf)
.WithOptional(p => p.Photo);
Run Code Online (Sandbox Code Playgroud)

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 );
}
Run Code Online (Sandbox Code Playgroud)

这就是说LoyaltyUserDetails PIIUser属性是必需的,PIIUser的LoyaltyUserDetail属性是可选的.

你可以从另一端开始:

modelBuilder.Entity<PIIUser>()
.HasOptional(pi => pi.LoyaltyUserDetail)
.WithRequired(lu => lu.PIIUser);
Run Code Online (Sandbox Code Playgroud)

现在说PIIUser的LoyaltyUserDetail属性是可选的,并且需要LoyaltyUser的PIIUser属性.

你总是必须使用模式HAS/WITH.

HTH和FWIW,一对一(或一对零/一)关系是最先在代码中配置的最令人困惑的关系之一,因此您并不孤单!:)

  • 嗨,是否可以先使用EF代码将0..1设置为0..1关系,以便仅在关系的一侧具有导航属性? (2认同)

小智 24

如果你之间有一对多的关系就好了LoyaltyUserDetail,PIIUser所以你应该映射

modelBuilder.Entity<LoyaltyUserDetail>()
       .HasRequired(m => m.PIIUser )
       .WithMany()
       .HasForeignKey(c => c.LoyaltyUserDetailId);
Run Code Online (Sandbox Code Playgroud)

EF应该创建你需要的所有外键,而不关心WithMany!

  • Julie Lerman的回答被接受了(并且应该保持被接受,恕我直言),因为它回答了这个问题并详细说明了为什么这是支持细节和讨论的正确方法.复制和粘贴答案当然可以在SO上使用,我自己也使用了一些,但作为一名专业开发人员,你应该更关心成为一名更好的程序员,而不仅仅是编写代码.也就是说,尽管一年后,jr做对了. (3认同)