如何 select 记录回外键

how to select records back on foreign keys

我正在尝试 select 记录来自 table 的记录,这些记录与单个记录匹配相同的外键。我写了以下 SQL 有效但我想知道是否有更优化的方法:

SELECT title FROM table1 r INNER JOIN dbo.table2 a ON a.Id = r.AssetStructureId 
                              INNER JOIN table3 s ON s.Id = a.table3id 
                              INNER JOIN dbo.table4 f ON f.Id = s.table4id
WHERE s.table4id = (SELECT f.Id FROM dbo.table4 f 
                                     INNER JOIN table3 s ON s.table4id = f.Id 
                                     INNER JOIN dbo.table2 a ON a.table3id = s.Id 
                                     INNER JOIN dbo.table1 r ON r.table2id = a.Id WHERE r.id = 21803)

我在entity framework里也写了同样的东西,但是写了两行,但我想知道是否还有更好、更优化的方法?

var data = _context.table1.Where(x => x.Id == id).Select(x => new { x.table2.table3.table4id }).SingleOrDefault();
var titles = _context.table1.Where(x => x.table2.table3.table4Id == data.table4id).Select(x => new { x.Title });

如有任何帮助,我们将不胜感激。

遗憾的是您忘了给我们您的 类 和规格!

在尝试了解你的 SQL 之后,似乎 table1 有一个 AssetStructureId,它是 Table2 的外键 Table1属于。可能是一对多关系。

Table2 有一个外键 Table3Id 到你的 Table2 所属的 Table3,也是一对多关系

最后 Table3 有一个外键 Table4IdTable3 所属的 Table4

我的天,您确实喜欢标识符的专有名称,不是吗?

所以:

  • 每个 Table4Element 有零个或多个 Table3Elements;
  • 每个 Table3Element 有零个或多个 Table2Elements;
  • 每个 Table2Element 有零个或多个 Table1Elements

entity framework code-first conventions 之后,您将 类 类似于:

class Table4Element
{
     public int Id {get; set;}

     // every Table4Element has zero or more Table3Elements:
     public virtual ICollection<Table3Element> Table3Elements {get; set;}

     ... // other properties
}
class Table3Element
{
     public int Id {get; set;}

     // every Table3Element has zero or more Table2Elements:
     public virtual ICollection<Table2Element> Table2Elements {get; set;}

     // every Table3Element belongs to exactly one Table4Element using foreign key
     public int Table4ElementId {get; set;}
     public virtual Table4Element Table4Element {get; set;}

     ...
}

In entity framework the columns of your tables are represented by non-virtual properties; the virtual properties represent the relations between the tables.

Table2Table1类似:

class Table2Element
{
     public int Id {get; set;}

     // every Table2Element has zero or more Table1Elements:
     public virtual ICollection<Table1Element> Table1Elements {get; set;}

     // every Table2Element belongs to exactly one Table3Element using foreign key
     public int Table3ElementId {get; set;}
     public virtual Table3Element Table3Element {get; set;}

     ...
}

class Table1Element
{
     public int Id {get; set;}

     // every Table1Element belongs to exactly one Table2Element using foreign key
     public int Table2ElementId {get; set;}
     public virtual Table2Element Table2Element {get; set;}

     ...
}

最后是你的 DbContext:

class MyDbContext : DbContext
{
    public DbSet<Table1Element> Table1Elements {get; set;}
    public DbSet<Table2Element> Table2Elements {get; set;}
    public DbSet<Table3Element> Table3Elements {get; set;}
    public DbSet<Table4Element> Table4Elements {get; set;}
}

这就是 entity framework 确定 table 的名称和列以及 table 之间的关系所需的全部内容。如果出于某种原因您想要不同的 table 名称或列,则需要添加属性或使用流畅的 API.

最重要的是你的虚拟属性是正确的。
无论何时你使用虚拟属性,entity framework都知道需要(组)加入并会为您完成

现在我们已经定义了您的四个 table,我们可以开始了

回到你的问题

糟糕,您忘记指定您想要的内容 select!

显然你的四个 table 之一有一个 Title。虽然你没说,但我认为TitleTable1的属性。看起来你有 Table1ElementId 你想要 select 拥有这个 Table1Element[=50 的 Table4Title =]

输入:RequestedId = 21803

  • Id 为 A 的 Table4Element 有一个 Title
  • 具有外键的 Table3Element Table4ElementId A 具有 ID B
  • 带外键的 Table2Element Table3ElementId B 的 ID C
  • 带外键的 Table1Element Table3ElementId C 的 ID 为 21803

你想要Title.

使用虚拟属性使查询变得简单。 Entity Framework 将为您进行连接:

int requestedId = 21803;
var requestedTitle = myDbContext.Table1Elements              // from all Table1 elements
    .Where(table1Element => table1Element.Id = requestedId)  // keep the one with the requestedId
    .Select(table1Element = table1Element                    // and select the Title
                           .Table2Element                    // of the Table4 element
                           .Table3element                    // that it belongs to
                           .Table4Element
                           .Title)
    .FirstOrDefault();  // You know there is only one

非常直观易懂。

我不知道为什么,但有些人坚持自己进行连接。使用方法语法与四个 tables 的连接看起来很可怕:

 int requestedId = 21803;
var requestedTitle = myDbContext.Table1Elements              // from all Table1Elements
    .Where(table1Element => table1Element.Id = requestedId)  // keep the one with the requestedId
    .Join(myDbContext.Table2Elements,                        // join with Table2Elements
    table1Element => table1Element.Table2ElementId,          // from Table1 take the foreign key
    table2Element => table2Element.Id,                       // from Table2 take the primary key
    (table1Element, table2Element) => table2Element)         // when they match keep the Table2
    .Join(myDbContext.Table3Elements,                        // to join with Table3
    table2Element => table2Element.Table3ElementId,          // foreign key to Table3
    table3Element => table3Element.Id,                       // primary key
    (table2Element, table3Element) => table3Element)         // keep table3Element
    .Join(myDbContext.Table4Elements,                        // to join with Table4
    table3Element => table3Elemen.Table4ElementId,           // foreign key
    table4Element => table4Element.Id,                       // primary key
    (table3Element, table4Element) => table4Element.Title)   // keep the Title
    .FirstOrDefault();                                       // expect only one element

,但仍然不如使用虚拟属性简单直观。仍然是你说服你的老板,你select的方法是最好理解、测试和维护的