使用EF Core创建另一个实体中唯一键的外键

时间:2017-06-25 00:52:13

标签: asp.net-core entity-framework-core

我有像这样的程序实体

public class Program : IEntityBase
{
    public int Id { get; set; }
    public string ProgramCode { get; set; }
    public string Name { get; set; }
    public int DegreeTypeID { get; set; }
    public DegreeType DegreeType { get; set; }
}

将programCode创建为具有此实现的唯一键

protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
        builder.Entity<Program>().HasAlternateKey(d => d.ProgramCode).HasName("AK_ProgramCode");
    }

我有另一个具有此定义的实体ApplicantProgram

public class ApplicantProgram : IEntityBase
{
    public int Id { get; set; }
    public int ApplicantID { get; set; }
    public Applicant Applicant { get; set; }
    [Required]
    public string FirstChoiceID { get; set; }
    [Required]
    public string SecondChoiceID { get; set; }
    [Required]
    public string ThirdChoiceID { get; set; }
    public string SessionID { get; set; }
}

其中包含FirstChoiceID,SecondChoiceID&amp; ThirdChoiceID在程序表中有ProgramCode。 现在这些是我的问题,

  1. 如何从ApplicantProgram获取Program.Name属性,知道要链接到Program.ProgramCode的FirstChoiceID?
  2. 是否可以从ApplicantProgram创建一个Navigation属性来编程?
  3. 如何在不使用Program.Id的情况下根据应该链接到Program.ProgramCode的ChoiceID创建从ApplicantProgram到Program的外键?
  4. 感谢您暂停阅读此内容。

1 个答案:

答案 0 :(得分:1)

  

(1)如何知道要链接到Program.ProgramCode的FirstChoiceID,从ApplicantProgram获取Program.Name属性?

此处没有特定于EF的内容,您可以使用典型的数据关联运算符 - join。仅仅因为你有3个相关的属性,你也需要3 join

var query =
    from applicantProgram in db.ApplicantPrograms
    join firstChoice in db.Programs on applicantProgram.FirstChoiceID equals firstChoice.ProgramCode
    join secondChoice in db.Programs on applicantProgram.SecondChoiceID equals secondChoice.ProgramCode
    join thirdChoice in db.Programs on applicantProgram.ThirdChoiceID equals thirdChoice.ProgramCode
    select new
    {
        ApplicantProgram = applicantProgram,
        FirstChoice = firstChoice,
        SecondChoice = secondChoice,
        ThirdChoice = thirdChoice,
    };

select内,您可以获得上述所有相关对象,或firstChoice.NamesecondChoice.Name等特定属性。

但是,一旦定义导航属性,您就不会需要EF中的所有内容,这导致我们:

  

(2)是否可以从ApplicantProgram创建一个Navigation属性来编程?

     

(3)如何在不使用Program.Id的情况下根据应该链接到Program.ProgramCode的ChoiceID从ApplicantProgram到Program创建外键?

这两者是相互关联的。虽然可以在没有导航属性的情况下定义FK,但导航属性允许您简单地访问LINQ查询中的相关实体属性,以及将相关实体作为使用它的实体的一部分进行简单的急切加载。

首先在ApplicantProgram类中添加3个导航属性(每个FK属性一个):

public Program FirstChoice { get; set; }
public Program SecondChoice { get; set; }
public Program ThirdChoice { get; set; }

以及以下流畅的配置:

builder.Entity<ApplicantProgram>()
    .HasOne(e => e.FirstChoice)
    .WithMany()
    .HasForeignKey(e => e.FirstChoiceID)
    .HasPrincipalKey(e => e.ProgramCode)
    .OnDelete(DeleteBehavior.Restrict);

builder.Entity<ApplicantProgram>()
    .HasOne(e => e.SecondChoice)
    .WithMany()
    .HasForeignKey(e => e.SecondChoiceID)
    .HasPrincipalKey(e => e.ProgramCode)
    .OnDelete(DeleteBehavior.Restrict);

builder.Entity<ApplicantProgram>()
    .HasOne(e => e.ThirdChoice)
    .WithMany()
    .HasForeignKey(e => e.ThirdChoiceID)
    .HasPrincipalKey(e => e.ProgramCode)
    .OnDelete(DeleteBehavior.Restrict);

我们这里有标准many-to-one关系配置 - HasOne(...)指定引用导航属性WithMany()指定没有相应的集合导航属性HasForeighKey(...)指定对应的FK属性,还有典型的多个关系到同一个表关闭级联删除以避免多个级联路径问题。

具体的想法(以及对EF6的EF核心改进)是HasPrincipalKey(...)方法,它允许您指定其他唯一键属性而不是PK(默认情况下)由FK关系使用。与另一端的HasAlternateKey(...)组合允许实现所需的FK关系设置。

基本上就是这样。现在来自(1)的查询可能只是

var query =
    from applicantProgram in db.ApplicantPrograms
    select new
    {
        applicantProgram,
        firstChoice = applicantProgram.FirstChoice,
        secondChoice = applicantProgram.SecondChoice,
        thirdChoice = applicantProgram.ThirdChoice,
    };

与(1)类似,您可以投影整个相关对象或仅需要属性。

或者,您可以通过将ApplicantProgram运算符添加到Program查询(所谓的eager loading)来获取已填充相关Include属性的ApplicantProgram个实例:

var query = db.ApplicantPrograms
    .Include(applicantProgram => applicantProgram.FirstChoice)
    .Include(applicantProgram => applicantProgram.SecondChoice)
    .Include(applicantProgram => applicantProgram.ThirdChoice);