Я ищу ответ на конкретную проблему выборки всей иерархии объектов LINQ с помощью одного SELECT.
Сначала я пытался заполнить как можно больше объектов LINQ, используя LoadOptions, но AFAIK этот метод позволяет связывать только одну таблицу в одном запросе, используя LoadWith. Итак, я изобрел решение для принудительной установки всех родительских объектов сущности, какой из списка должен быть выбран, хотя существует проблема с несколькими SELECTS, поступающими в базу данных - один запрос приводит к двум SELECTS с одинаковыми параметрами в одном и том же контексте LINQ .
Для этого вопроса я упростил этот запрос для примера популярного счета:
public static class Extensions
{
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> collection, Action<T> func)
{
foreach(var c in collection)
{
func(c);
}
return collection;
}
}
public IEnumerable<Entry> GetResults(AppDataContext context, int CustomerId)
{
return
(
from entry in context.Entries
join invoice in context.Invoices on entry.EntryInvoiceId equals invoice.InvoiceId
join period in context.Periods on invoice.InvoicePeriodId equals period.PeriodId
// LEFT OUTER JOIN, store is not mandatory
join store in context.Stores on entry.EntryStoreId equals store.StoreId into condStore
from store in condStore.DefaultIfEmpty()
where
(invoice.InvoiceCustomerId = CustomerId)
orderby entry.EntryPrice descending
select new
{
Entry = entry,
Invoice = invoice,
Period = period,
Store = store
}
).ForEach(x =>
{
x.Entry.Invoice = Invoice;
x.Invoice.Period = Period;
x.Entry.Store = Store;
}
).Select(x => x.Entry);
}
При вызове этой функции и обходе набора результатов, например:
var entries = GetResults(this.Context);
int withoutStore = 0;
foreach(var k in entries)
{
if(k.EntryStoreId == null)
withoutStore++;
}
результирующий запрос к базе данных выглядит следующим образом (извлекается один результат):
SELECT
[t0].[EntryId],
[t0].[EntryInvoiceId],
[t0].[EntryStoreId],
[t0].[EntryProductId],
[t0].[EntryQuantity],
[t0].[EntryPrice],
[t1].[InvoiceId],
[t1].[InvoiceCustomerId],
[t1].[InvoiceDate],
[t1].[InvoicePeriodId],
[t2].[PeriodId],
[t2].[PeriodName],
[t2].[PeriodDateFrom],
[t4].[StoreId],
[t4].[StoreName]
FROM
[Entry] AS [t0]
INNER JOIN [Invoice] AS [t1] ON [t0].[EntryInvoiceId] = [t1].[InvoiceId]
INNER JOIN [Period] AS [t2] ON [t2].[PeriodId] = [t1].[InvoicePeriodId]
LEFT OUTER JOIN (
SELECT 1 AS [test], [t3].[StoreId], [t3].[StoreName]
FROM [Store] AS [t3]
) AS [t4] ON [t4].[StoreId] = ([t0].[EntryStoreId])
WHERE (([t1].[InvoiceCustomerId]) = @p0)
ORDER BY [t0].[InvoicePrice] DESC
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [186]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 3.5.30729.1
SELECT
[t0].[EntryId],
[t0].[EntryInvoiceId],
[t0].[EntryStoreId],
[t0].[EntryProductId],
[t0].[EntryQuantity],
[t0].[EntryPrice],
[t1].[InvoiceId],
[t1].[InvoiceCustomerId],
[t1].[InvoiceDate],
[t1].[InvoicePeriodId],
[t2].[PeriodId],
[t2].[PeriodName],
[t2].[PeriodDateFrom],
[t4].[StoreId],
[t4].[StoreName]
FROM
[Entry] AS [t0]
INNER JOIN [Invoice] AS [t1] ON [t0].[EntryInvoiceId] = [t1].[InvoiceId]
INNER JOIN [Period] AS [t2] ON [t2].[PeriodId] = [t1].[InvoicePeriodId]
LEFT OUTER JOIN (
SELECT 1 AS [test], [t3].[StoreId], [t3].[StoreName]
FROM [Store] AS [t3]
) AS [t4] ON [t4].[StoreId] = ([t0].[EntryStoreId])
WHERE (([t1].[InvoiceCustomerId]) = @p0)
ORDER BY [t0].[InvoicePrice] DESC
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [186]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 3.5.30729.1
Вопрос в том, почему есть два запроса и как я могу получить объекты LINQ без таких хаков?