0

This might have been asked a few times and I indeed found a few questions (one or two) with the same subject. However those questions were rather old aswell as the fact they remained unaswered.

Basically I've got a QueryOver (tried to get the same result with Linq to NHibernate but apperently a bit to complex for the 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>();

The biggest problem is that for the life of me I can't get the grouping out of the select, I only want the ID of the printjob type returned but I can't seem to be able to get that to work. This query basically Sorta by PrintJobWeight first and the Min Printjob ID second.

(So the current query looks like:)

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

So I'd basically like to only return the ID of the printjobtype.

As a 'bonus' what we really want is select the PrintJobType in it's entirety since as it currently stands I have to do a .Load(id) call right after selecting the list which to me also seems rather redundant but I could live with that but the current result just seems super inefficient to me.

Meaning in a perfect world the query hitting the server would look like:

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

(Yes you can't put a printjobty1_.* in the group by clause but it's quicker then writting down all the properties and things by hand)

NHibernate version: 3.3.1.4000 - SQL Server 2012

F.B. ten Kate
  • 2,032
  • 2
  • 21
  • 31
  • Is there a mapped association from `PrintJobType` to `PrintJob`? – Andrew Whitaker Aug 16 '14 at 16:50
  • Nope, as that relation is normally not used we had no real reason to map it. Although I did think about mapping it to make the query.... easier :) Only reason we have to use the Min thing now is because we noticed the order of printing (since all jobs have the same weight atm) left 'old' jobs for a rather long time sometimes which is not desired. – F.B. ten Kate Aug 16 '14 at 16:59

1 Answers1

0

Desired solution with NHibernate would use a subquery. That way we can firstly get the ID we need (Grouping, sorting, filtering) and then use that ID to get the clear result. Please observe the power of NHibernate and Subqueries here:

I am not 100% sure what you want to get, but there is a draft of the solution:

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>();

Now, for some test purposes, we can continue:

// 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);
Community
  • 1
  • 1
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • Well, we want to select a list of all printjobtypes that have jobs to print, ordered by the Weight, followed by the min printjob ID that has not yet been printed. Your solution is close though and I think I might be able to adjust it to that purpose. – F.B. ten Kate Aug 17 '14 at 08:12
  • Actually, trying some things now, this won't work. I can get the PrintJobIDs ordered by the list mentioned, however I need the distinct PrintJobTypes not PrintJobs. The query I need I've almost got except for the fact that the Group By part with 'PriorityWeight' is in the Select statement aswell which is absolutelypointless as I don't need it. If I can get rid of this part of the select I can use your subquery method to get the PrintJobTypes I need. – F.B. ten Kate Aug 17 '14 at 08:52
  • Wish to help more, but I still cannot see what is the issue. In the link I've gave you in the answer, you can see, that almost any SUB-Query we can build with NHibernate. So, maybe, firstly try to think how the correct SQL query should look like. Then, reinvestigate that construct... and you will succeed. But if this won't work in pure SQL ... for sure it won't work in NHibernate - unless we will use more queries and some C# handling... good luck anyhow ;) – Radim Köhler Aug 17 '14 at 09:15
  • Ow no, I can easily get this to work in pure SQL. The problem lies in the first Query i've posted, you can see the group by and the order by... the problem is in the SELECT part. The order by and group by is perfect. I simply only need the ID, and not the Weight in the select (I do need those in the group by and order by though) – F.B. ten Kate Aug 17 '14 at 12:26
  • I mean: pure SQL with the subquery. The trick is: firstly find the ID of the `PrintJob` - inside of the subquery. Next step is: filter the *simple/root* query with that subquery. That's it, this is the way how you can achieve that kind of selection with NHibernate... wish that helped somehow, but I still feel that you do not see exactly what I am trying to express.. really sorry that I cannot explain that more clear... good luck anyhow.. – Radim Köhler Aug 17 '14 at 13:48