Написание метода расширения для регулярно используемых запросов в Entity Framework (Core)? - PullRequest
0 голосов
/ 22 октября 2018

Существует общий шаблон, который я использую во многих моих запросах 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-запрос?

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