C # Linq несколько запросов в одном - PullRequest
0 голосов
/ 11 сентября 2018

Я новичок в Linq и пытаюсь оптимизировать некоторые запросы, и я понятия не имею, возможно ли это для этих запросов:

var cSRez = (from l in MyTable
                 where l.Name == "dcc" && l.Service == "Main"
                 orderby l.Time descending
                 select l.Value).FirstOrDefault();
var cDRez = (from l in MyTable
                 where l.Name == "dcc" && l.Service == "DB"
                 orderby l.Time descending
                 select l.Value).FirstOrDefault();
var dSRez = (from l in MyTable
                 where l.Name == "ddc" && l.Service == "Main"
                 orderby l.Time descending
                 select (long?)l.Value).FirstOrDefault();
var dDRez = (from l in MyTable
                 where l.Name == "ddc" && l.Service == "DB"
                 orderby l.Time descending
                 select (long?)l.Value).FirstOrDefault();
var mSRez = (from l in MyTable
                  where l.Name == "mc" && l.Service == "Main"
                  orderby l.Time descending
                  select l.Value).FirstOrDefault();
var mDRez = (from l in MyTable
                  where l.Name == "mc" && l.Service == "DB"
                  orderby l.Time descending
                  select l.Value).FirstOrDefault();

, чтобы стать одним. Я думал о row_number() over(partition by... (SQL), но не думаю, что это лучшая идея для этого.

Возможно ли объединить эти шесть отдельных запросов в один?

Ответы [ 4 ]

0 голосов
/ 11 сентября 2018

Я не уверен, будет ли он выполняться быстрее как один запрос или нет, так как запрос несколько сложен, поэтому я думаю, что это может зависеть от времени запроса на стороне сервера в зависимости от настройки запроса и времени передачи данных.

Вы можете преобразовать в один запрос, который собирает все ответы сразу, а затем разбить этот ответ для каждой переменной.

Этот первый ответ принимает результат и преобразуется в двойное вложенное значение Dictionary для значений, а затем извлекает переменные из Dictionary:

var ansd = (from l in MyTable
            where new[] { "dcc", "ddc", "mc" }.Contains(l.Name) && new[] { "Main", "DB" }.Contains(l.Service)
            group l by new { l.Name, l.Service } into ag
            select new {
                ag.Key.Name,
                ag.Key.Service,
                Value = ag.OrderByDescending(l => l.Time).First().Value
            })
            .GroupBy(nsv => nsv.Name)
            .ToDictionary(nsvg => nsvg.Key, nsvg => nsvg.ToDictionary(nsv => nsv.Service, arv => arv.Value));

long? cSRez = null, cDRez = null, dSRez = null, dDRez = null, mSRez = null, mDRez = null;
if (ansd.TryGetValue("dcc", out var td)) td.TryGetValue("Main", out cSRez);
if (ansd.TryGetValue("dcc", out td)) td.TryGetValue("DB", out cDRez);
if (ansd.TryGetValue("ddc", out td)) td.TryGetValue("Main", out dSRez);
if (ansd.TryGetValue("ddc", out td)) td.TryGetValue("DB", out dDRez);
if (ansd.TryGetValue("mc", out td)) td.TryGetValue("Main", out mSRez);
if (ansd.TryGetValue("mc", out td)) td.TryGetValue("DB", out mDRez);

Учитывая, что ответов всего шесть, создание Dictionary для них может оказаться излишним. Вместо этого вы можете просто (последовательно) найти соответствующие ответы:

var ansl = (from l in MyTable
            where new[] { "dcc", "ddc", "mc" }.Contains(l.Name) && new[] { "Main", "DB" }.Contains(l.Service)
            group l by new { l.Name, l.Service } into ag
            select new {
                ag.Key.Name,
                ag.Key.Service,
                Value = ag.OrderByDescending(l => l.Time).First().Value
            })
            .ToList();

var cSRez = ansl.FirstOrDefault(ansv => ansv.Name == "dcc" && ansv.Service == "Main");
var cDRez = ansl.FirstOrDefault(ansv => ansv.Name == "dcc" && ansv.Service == "DB");
var dSRez = ansl.FirstOrDefault(ansv => ansv.Name == "ddc" && ansv.Service == "Main");
var dDRez = ansl.FirstOrDefault(ansv => ansv.Name == "ddc" && ansv.Service == "DB");
var mSRez = ansl.FirstOrDefault(ansv => ansv.Name == "mc" && ansv.Service == "Main");
var mDRez = ansl.FirstOrDefault(ansv => ansv.Name == "mc" && ansv.Service == "DB");
0 голосов
/ 11 сентября 2018

Я не уверен, как EF переведет этот запрос в SQL, но я бы попробовал такой подход:

var rawData = MyTable
    .Where(l => (l.Name=="dcc" || l.Name=="ddc" || l.Name=="mc") && (l.Service=="Main" || l.Service=="Db"))
    .GroupBy(l => new { l.Name, l.Service })
    .Select(g => g.OrderByDescending(l => l.Time).First())
    .ToList();

Это должно дать до шести строк, представляющих интерес для вашей программы.Теперь вы можете извлечь каждую строку, указав конкретную комбинацию Name и Service:

var cSRez = rawData.FirstOrDefault(l => l.Name == "dcc" && l.Service == "Main");
var cDRez = rawData.FirstOrDefault(l => l.Name == "dcc" && l.Service == "DB");
var dSRez = rawData.FirstOrDefault(l => l.Name == "ddc" && l.Service == "Main");
var dDRez = rawData.FirstOrDefault(l => l.Name == "ddc" && l.Service == "DB");
var mSRez = rawData.FirstOrDefault(l => l.Name == "mc" && l.Service == "Main");
var mDRez = rawData.FirstOrDefault(l => l.Name == "mc" && l.Service == "DB");

Обратите внимание, что шесть запросов на rawData выполняются в памяти в списке фиксированного размера додо шести предметов, поэтому они не будут стоить вам дополнительных поездок в RDBMS.

0 голосов
/ 11 сентября 2018

Просто поместите ваш запрос в закрытый метод, который принимает Exression и возвращает Value и вызывает его для каждой переменной (например, cDRez, cSRez и т. Д.), Просто передавая различные выражения.

private Value GetValue(Expression<Func<MyTable, bool>> filter) {
    return MyTable.Where(filter).OrderByDescending(o => o.Time).Select(s => s.Value).FirstOrDefault();
}

Назовите это как различные фильтры для каждой переменной:

var cSRez = GetValue(l => l.Name == "dcc" && l.Service == "Main");
var cDRez = GetValue(l => l.Name == "dcc" && l.Service == "DB");
var dSRez = GetValue(l => l.Name == "ddc" && l.Service == "Main");
var dDRez = GetValue(l => l.Name == "ddc" && l.Service == "DB");
var mSRez = GetValue(l => l.Name == "mc" && l.Service == "Main");
var mDRez = GetValue(l => l.Name == "mc" && l.Service == "DB");
0 голосов
/ 11 сентября 2018

Вам нужно сгруппировать по Имени и Службе, а затем отфильтровать по определенным парам, которые вы хотите, затем выберите Имя и Службу и Значение из Первого совпадения. Обратите внимание, что любые несуществующие пары не будут представлены в результатах, и вам придется справиться с этим при извлечении значений.

var results = (from l in MyTable
              group l by new {l.Name, l.Service} into grp
              where (grp.Key.Name == "dcc" && grp.Key.Service == "Main")
                  || (grp.Key.Name == "dcc" && grp.Key.Service == "DB")
                  || ....
              select new
              {
                  grp.Key,
                  Value = grp.OrderByDescending(x => x.Time).Select(x => x.Value).First()
              }).ToDictionary(x => x.Key, x => x.Value);

Затем вытащить результаты

results.TryGetValue(new { Name = "dcc", Service = "Main" }, out var cSRez);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...