【问题标题】:LINQ - outer join to parent class in EF code firstLINQ - 首先在 EF 代码中外部连接到父类
【发布时间】:2016-02-06 11:19:00
【问题描述】:

我认为我在这里遗漏了一些基本的东西。

我有以下 EF 代码优先实体:公司和调制解调器。公司可以有一个调制解调器列表。

 public class Company
    {
        public int ID { get; set; }
        ...
        public virtual ICollection<Modem> Modems { get; set:}
    }  


 public class Modem
    {
        public int ID { get; set; }
        ...

    }

这会在Modem 表上生成一个列Company_ID 作为外键。

我想退回所有调制解调器及其公司 ID(如果有)。 在 SQL 中,我会执行以下操作:

select * from Modem m
left outer join Company c on 
m.Company_ID = c.ID

我熟悉在 LINQ 中使用 .DefaultIfEmpty() 在 DB 优先而不是代码优先中进行左外连接。

我的困惑是我在 LINQ 中没有可用的 m.Company_ID 来执行连接,因为它是由 EF 自动生成的。

如何在 LINQ 中执行此连接?

【问题讨论】:

  • 为什么你的Modem 类没有引用Company?喜欢public Company Company { get; set;}
  • 您尝试过类似... db.Companies.SelectMany(c => c.Modems) 吗?其中 db 是您的实体
  • @avi 听起来有些调制解调器没有链接到公司,因为 OP 想离开加入公司。
  • @juharr,正确的。某些调制解调器未与公司关联。

标签: c# linq ef-code-first outer-join


【解决方案1】:

EF 的真正美妙之处在于您根本不需要考虑连接(嗯,大多数时候)。您只需通过导航属性正确定义实体及其关系。例如,这里是一个类似于你的模型的定义:

public class Company
{
    public int ID { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Modem> Modems { get; set; }
}

public class Modem
{
    public int ID { get; set; }
    public string Name { get; set; }
    public virtual Company Company { get; set; }
}

public class MyDbContext : DbContext
{
    public DbSet<Company> Companies { get; set; }
    public DbSet<Modem> Modems { get; set; }
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Company>()
            .HasMany(company => company.Modems)
            .WithOptional(modem => modem.Company)
            .Map(action => action.MapKey("Company_ID"));
        base.OnModelCreating(modelBuilder);
    }
}

注意Company.ModemsModem.Company属性,以及关系的流畅配置,包括FK列的名称。

现在,如果我们执行以下操作

using (var db = new MyDbContext())
{
    var query = db.Modems.Select(m => new { Modem = m, CompanyName = m.Company.Name });
    var sqlQuery = query.ToString();
}

sqlQuery 变量包含

SELECT 
    [Extent1].[ID] AS [ID], 
    [Extent1].[Name] AS [Name], 
    [Extent1].[Company_ID] AS [Company_ID], 
    [Extent2].[Name] AS [Name1]
    FROM  [dbo].[Modems] AS [Extent1]
    LEFT OUTER JOIN [dbo].[Companies] AS [Extent2] ON [Extent1].[Company_ID] = [Extent2].[ID]

你去 - 希望你看到你要求的 LEFT OUTER 加入。

【讨论】:

  • 唯一要补充的是,在访问Company 属性时,您需要小心并检查空引用。在 C# 5 中:var query = db.Modems.Select(m =&gt; new { Modem = m, CompanyName = m.Company == null ? string.Empty : m.Company.Name }); 在 C# 6 中:var query = db.Modems.Select(m =&gt; new { Modem = m, CompanyName = m.Company?.Name });
  • 很好的例子。导航属性是我缺少的概念,因为我错误地认为这些是自动创建的。
猜你喜欢
  • 2012-02-01
  • 2013-05-16
  • 1970-01-01
  • 2011-10-26
  • 2023-04-05
  • 2011-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多