NHibernate QueryOver помещает группу в выбор

Это, возможно, задавали несколько раз, и я действительно нашел несколько вопросов (один или два) на ту же тему. Однако эти вопросы были довольно стары, а также тот факт, что они остались без ответа.

По сути, я получил QueryOver (пытался получить тот же результат с Linq для NHibernate, но немного сложнее для Linq):

PrintJobType printJobType = null;
var test = unitOfWork.Session.QueryOver<PrintJob>()
  .JoinAlias(pj => pj.PrintJobType, () => printJobType)
  .Where(pj => pj.PrintedOn == null)
  .Select(Projections.ProjectionList()
            .Add(Projections.Group(() => printJobType.PriorityWeight))
            .Add(Projections.Group(() => printJobType.ID)))
  .OrderBy(pj => printJobType.PriorityWeight).Desc
  .OrderBy(Projections.Min<PrintJob>(pj => pj.ID)).Asc
  .List<object[]>()
  .Select(x => x[1])
  .Cast<int>();

Самая большая проблема заключается в том, что я не могу вынести группировку из списка, поскольку мне нужно только вернуть идентификатор типа printjob, но я не могу заставить его работать. Этот запрос в основном сортируется сначала PrintJobWeight и вторым идентификатором Min Printjob.

(Так выглядит текущий запрос:)

SELECT 
    printjobty1_.PriorityWeight as y0_, printjobty1_.ID as y1_ 
FROM 
    [PrintJob] this_ 
    inner join [PrintJobType] printjobty1_ on this_.PrintJobType_id=printjobty1_.ID 
WHERE 
    this_.PrintedOn is null 
GROUP BY 
    printjobty1_.PriorityWeight, 
    printjobty1_.ID 
ORDER BY 
    printjobty1_.PriorityWeight desc, 
    min(this_.ID) asc

Поэтому я бы хотел вернуть только идентификатор типа printjob.

В качестве "бонуса" мы действительно хотим выбрать PrintJobType целиком, поскольку в его нынешнем виде я должен сделать вызов.Load(id) сразу после выбора списка, который мне также кажется излишним, но я мог бы с этим смириться. но текущий результат мне кажется просто неэффективным.

То есть в идеальном мире запрос к серверу будет выглядеть так:

SELECT 
    printjobty1_.*
FROM 
    [PrintJob] this_ 
    inner join [PrintJobType] printjobty1_ on this_.PrintJobType_id=printjobty1_.ID 
WHERE 
    this_.PrintedOn is null 
GROUP BY 
    printjobty1_.*
ORDER BY 
    printjobty1_.PriorityWeight desc, 
    min(this_.ID) asc

(Да, вы не можете поместить printjobty1_.* В предложение group by, но это быстрее, чем записывать все свойства и вещи вручную)

Версия NHibernate: 3.3.1.4000 - SQL Server 2012

1 ответ

Желаемое решение с NHibernate будет использовать подзапрос. Таким образом, мы можем сначала получить нужный нам идентификатор (группировка, сортировка, фильтрация), а затем использовать этот идентификатор для получения четкого результата. Пожалуйста, обратите внимание на силу NHibernate и подзапросов здесь:

Я не уверен на 100%, что вы хотите получить, но есть черновик решения:

PrintJob printJob = null;
PrintJobType printJobType = null;

// simply this is the place, where we do all the magic
// to select the PrintJob.ID
// I guess that my adjustments would result in the same stuff 
// as in the query above without the grouping
// ... but if not, we still do have a draft of HOW TO
var subQuery = QueryOver.Of<PrintJob>()
    .JoinAlias(pj => pj.PrintJobType, () => printJobType)
    .Where(pj => pj.MiddleName == null)
    .SelectList(l => l
        .Select(pj => pj.ID)
    )
    .OrderBy(() => printJobType.PriorityWeight).Desc
    .OrderBy(pj => pj.ID).Asc
    .Take(1)
    ;

// here we SELECT the clean, root object and its reference... 
// that all will be executed as only ONE Select statement
var result = session.QueryOver<PrintJob>(() => printJob)
    .WithSubquery
        .WhereProperty(() => printJob.ID)
        .In(subQuery)
    .JoinAlias(x => x.PrintJobType, () => printJobType)
    .SingleOrDefault<PrintJob>();

Теперь для некоторых целей тестирования мы можем продолжить:

// here we say session clear just for the TEST purposes below
session.Clear();

// now, session is closed, no lazy loading, but due to JOIN ALIAS
// the PrintJobType is loaded as well
Assert.IsTrue(result != null);
Assert.IsTrue(result.PrintJobType != null);
Assert.IsTrue(result.PrintJobType.PriorityWeight != null);
Другие вопросы по тегам