Существует общий шаблон, который я использую во многих моих запросах Entity Framework, и я хотел бы найти способ уменьшить количество повторений.(Я использую ядро EF, но я думаю, что это, вероятно, относится и к другим версиям.)
В основном у меня есть объект Resource
и объект Translation
.Для данного ресурса мне нужно получить перевод, желательно в текущей культуре, если он доступен, если не получится какой-то запасной вариант (возможно, английский), а если его нет, просто получите все, что доступно.
Шаблонпо сути это:
MyContext.Foos
.Where(f => f.Id > -1)
.Select(f => new {
FooId = f.Id,
Translation = f.Resource.Translations
.OrderBy(t => t.Culture == "fr" ? 1 : t.Culture == "en" ? 2 : 3)
.Select(t => t.Value)
.FirstOrDefault()
})
.ToList();
, что приводит к этому единственному запросу SQL:
SELECT [f].[Id], (
SELECT TOP(1) [b].[Value]
FROM [Translations] AS [b]
WHERE [f.Resource].[Id] = [b].[ResourceId]
ORDER BY CASE
WHEN [b].[Culture] = N'en'
THEN 1 ELSE CASE
WHEN [b].[Culture] = N'fr'
THEN 2 ELSE 3
END
END
) AS [x]
FROM [Foos] AS [f]
INNER JOIN [Resources] AS [f.Resource] ON [f].[ResourceId] = [f.Resource].[Id]
Множество различных объектов используют ресурсы, и я хотел бы иметь возможность привести это в порядок (и сделать его более СУХИМ), выполнив что-то вроде этого:
MyContext.Foos
// .Include(f => f.Resource.Translations)
.Where(f => f.Id > -1)
.Select(f => new {
FooId = f.Id,
Translation = f.Resource.GetTranslation("fr", "en")
})
.ToList();
public static string GetTranslation(this Resource resource, string primary, string secondary)
{
return resource.Translations
.OrderBy(t => t.Culture == "fr" ? 1 : t.Culture == "en" ? 2 : 3)
.Select(t => t.Value)
.FirstOrDefault()
}
Это фактически возвращает нулевые значения для переводов.Я попытался добавить .Includes(...)
безрезультатно.Я также попробовал эту альтернативу, которая вызывается для набора переводов, а не для объекта ресурса:
public static string GetTranslation(this IEnumerable<Translation> translations, string primary, string secondary)
{
return translations
.OrderBy(b => b.Culture == primary ? 1 : b.Culture == secondary ? 2 : 3)
.Select(b => b.Value)
.FirstOrDefault();
}
, который возвращает именно то, что я хочу, но он выполняет два запроса!Первый просто выбирает первичный ключ ресурсов:
SELECT [f.Resource].[Id]
FROM [Foos] AS [f]
INNER JOIN [Resources] AS [f.Resource] ON [f].[ResourceId] = [f.Resource].[Id]
WHERE [f].[Id] > -1
ORDER BY [f].[Id], [f.Resource].[Id]
А второй делает то, что мне нужно, но по сути снова запускает первый запрос:
SELECT [f.Resource.Translations].[Id], [f.Resource.Translations].[Culture], [f.Resource.Translations].[ResourceId], [f.Resource.Translations].[Value], [t].[Id], [t].[Id0]
FROM [Translations] AS [f.Resource.Translations]
INNER JOIN (
SELECT [f0].[Id], [f.Resource0].[Id] AS [Id0]
FROM [Foos] AS [f0]
INNER JOIN [Resources] AS [f.Resource0] ON [f0].[ResourceId] = [f.Resource0].[Id]
WHERE [f0].[Id] > -1
) AS [t] ON [f.Resource.Translations].[ResourceId] = [t].[Id0]
ORDER BY [t].[Id], [t].[Id0]
Есть ли какая-то записьметод расширения, который в основном служит сокращением для регулярно используемой последовательности операторов Linq, подобных этой, которая может быть преобразована в один SQL-запрос?