В Linq вам действительно нужно присоединиться очень редко:
var myQuery = _db.CustomFields
.Where(c => c.AnotherId == 1)
.Select(cf => new CustomFieldModel
{
CustomFieldId = cf.Id,
Name = cf.Name,
DataValue = cf.cd.Any(cd => cd.OutSideId == 180)
? cf.cd.First(cd => cd.OutSideId == 180).DataValue
: (<type?>)null;
}).ToList();
В LinqToSQL это сгенерирует SQL вроде:
DECLARE @p0 int = 1;
DECLARE @p1 Int = 180;
DECLARE @p2 Int = 180;
SELECT [t0].[CustomFieldId], [t0].[Name],
(CASE
WHEN EXISTS(
SELECT NULL AS [EMPTY]
FROM [CustomFieldDataItems] AS [t1]
WHERE ([t1].[OutsideID] = @p1) AND ([t1].[CustomFieldID] = [t0].[ID])
) THEN (
SELECT [t3].[DataValue]
FROM (
SELECT TOP (1) [t2].[DataValue]
FROM [CustomFieldDataItems] AS [t2]
WHERE ([t2].[OutsideID] = @p2) AND ([t2].[CustomFieldID] = [t0].[ID])
) AS [t3]
)
ELSE NULL
END) AS [DataValue]
FROM [CustomFields] AS [t0]
WHERE [t0].[AnotherId] = @p0
Это на самом деле не дает результата с вашим исходным SQL (я использовал First, чтобы получить DataValue, что означало бы, что вы не получите результат как 1-Many).
Тогда мы могли бы переписать его так, как в этой оптимизированной версии, которая также дает исходный результат, который вы изначально (не уверены, хотите ли вы повторять строки из пользовательских полей - ваш SQL делает):
var myQuery = (from cf in CustomFields
from cd in cf.CustomFieldDataItems.Where(d => d.OutsideId==180).DefaultIfEmpty()
where cf.AnotherId == 1
select new CustomFieldModel
{
CustomFieldId = cf.Id,
Name = cf.Name,
DataValue = cd == null?(int?)null:cd.DataValue,
AnotherValue = cd == null?(<typeName?>)null:cd.AnotherValue,
}).ToList();
Сгенерированный SQL будет выглядеть так:
DECLARE @p0 Int = 1;
DECLARE @p1 Int = 180;
SELECT [t0].[CustomFieldId], [t0].[Name],
(CASE
WHEN [t2].[test] IS NULL THEN NULL
ELSE [t2].[DataValue]
END) AS [DataValue],
(CASE
WHEN [t2].[test] IS NULL THEN NULL
ELSE [t2].[AnotherValue]
END) AS [AnotherValue]
FROM [CustomFields] AS [t0]
LEFT OUTER JOIN (
SELECT 1 AS [test], [t1].[DataValue], [t1].[CustomFieldID], [t1].[AnotherValue], [t1].[OutsideId]
FROM [CustomFieldDataItems] AS [t1]
) AS [t2] ON ([t2].[OutsideId] = @p0) AND ([t2].[CustomFieldID] = [t0].[ID])
WHERE [t0].[AnotherId] = @p1;
РЕДАКТИРОВАТЬ: Если подумать, это можно было бы упростить до:
var myQuery = (from cf in CustomFields
from cd in cf.CustomFieldDataItems.Where(d => d.OutsideId==180).DefaultIfEmpty()
where cf.AnotherId == 1
select new CustomFieldModel
{
CustomFieldId = cf.Id,
Name = cf.Name,
DataValue = (int?)cd.DataValue,
AnotherValue = (<typeName?>)cd.AnotherValue,
}).ToList();
Это сгенерирует SQL как:
DECLARE @p0 Int = 180;
DECLARE @p1 Int = 1;
SELECT [t0].[CustomFieldId], [t0].[Name],
[t1].[DataValue], [t1].[AnotherValue]
FROM [CustomFields] AS [t0]
LEFT OUTER JOIN [CustomFieldDataItems] AS [t1]
ON ([t1].[OutSideId] = @p0) AND ([t1].[CustomFieldID] = [t0].[ID])
WHERE [t0].[AnotherId] = @p1;
Почти такой же, как ваш.
Только для завершения как "лямбда":
var myQuery = _db.CustomFields
.Where (cf => cf.AnotherId == 1)
.SelectMany (
cf => cf.CustomFieldDataItems.Where (cd => (cd.OutsideId == (Int32?)180)).DefaultIfEmpty(),
(cf, cd) => new CustomFieldModel
{
CustomFieldId = cf.Id,
Name = cf.Name,
DataValue = (int?)cd.DataValue,
AnotherValue = (<typeName?>)cd.AnotherValue,
}
).ToList();