как отбирать записи обратно на внешние ключи - PullRequest
0 голосов
/ 17 октября 2018

Я пытаюсь выбрать записи записей из таблицы, которые соответствуют тому же внешнему ключу, что и отдельная запись.Я написал следующий 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)

Я также написал то же самое в рамках сущностей, но написал его в две строки, ноМне было интересно, был ли там лучший, более оптимальный путь?

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 });

Любая помощь будет принята с благодарностью.

1 Ответ

0 голосов
/ 17 октября 2018

Как жаль, что вы забыли дать нам ваши классы и ваши спецификации!

После попытки понять ваш SQL, кажется, что table1 имеет AssetStructureId, чтовнешний ключ к Table2, к которому принадлежит Table1.Вероятно, отношение «один ко многим».

Table2 имеет внешний ключ Table3Id к Table3, к которому принадлежит ваш Table2, также отношение «один ко многим»

Наконец Table3 имеет внешний ключ Table4Id для Table4, к которому принадлежит Table3.

Мое, вы любите собственные имена для своих идентификаторов, не так ли?

Итак:

  • Каждый Table4Element имеет ноль или более Table3Elements;
  • Каждый Table3Element имеет ноль или более Table2Elements;
  • Каждое Table2Element имеет ноль или более Table1Elements.

В соответствии с соглашениями по коду, принятыми в коде сущности , у вас будут классы, подобные:

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;}

     ...
}

В структуре сущностей столбцы ваших таблиц представлены не виртуальными свойствами;виртуальные свойства представляют отношения между таблицами.

Table2 и Table1 похожи:

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;}
}

Это все, что необходимо для определения структуры таблиц и столбцов и связей между таблицами.Если по какой-то причине вам нужны другие имена таблиц или столбцов, вам нужно добавить атрибуты или использовать свободный API.

Самое важное в этом - то, что вы правильно указали свои виртуальные свойства.
Всякий раз, когда вы используете виртуальные свойства, структура сущностей знает, что требуется (групповое) объединение, и сделает их для вас

Теперь, когда мы определили ваши четыре таблицы, мы можем перейти

Вернуться к вашему вопросу

Упс, вы забыли указать, что хотите выбрать!

Ну, очевидно, на одном из ваших четырех столов есть Title.Хотя вы этого не сказали, я думаю, что Title является свойством Table1.Кажется, у вас есть Id из Table1Element, который вы хотите выбрать Title из Table4, которому принадлежит Table1Element

Ввод: RequestedId = 21803

  • Table4Element с идентификатором A имеет Title
  • Table3Element с внешним ключом Table4ElementId A имеет идентификатор B
  • Table2Element с внешним ключом Table3ElementId B имеет идентификатор C
  • Table1Element с внешним ключом Table3ElementId C имеет идентификатор 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

Очень интуитивно понятный и простой для понимания.

Не знаю почему, но некоторые люди настаивают на том, чтобы эти объединения выполнялись сами.Используя синтаксис метода, соединение с четырьмя таблицами выглядит ужасно:

 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

Используя синтаксис запроса, этот запрос проще , но все же не так прост и интуитивно понятен, как использование виртуальных свойств.Тем не менее, вы должны убедить своего начальника в том, что выбранный вами метод лучше всего понять, протестировать и поддерживать

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...