Question

This is similar to this question: NHibernate - Implement "NOT IN" query using ICriteria

But that doesn't work for my solution.

I have an Order:

class Order
{
   DateTime CreatedDate { get; set;} 
   Person CreatedBy { get; set; }
}

and a Person:

class Person
{ 
   string Name { get; set;} // etc.
}

I want to retrieve all people that don't have orders within a date range. The SQL would end up like this:

SELECT *
FROM Person
WHERE Id NOT IN (SELECT PersonId
                 FROM Order
                 WHERE CreatedDate BETWEEN '2012-01-01' and '2012-01-31')

When I query with the solution provided in the above question, it fails if there are 2100 people or more (SQL won't allow that many parameters).

Also I can't add a Orders collection to person because that would involve pulling way too much data (I only want a date range).

How can I do this with NHibernate?

Was it helpful?

Solution

You can use a subquery...

var peopleWithOrdersInRange = QueryOver.Of<Order>()
    .WhereRestrictionOn(x => x.CreatedDate).IsBetween(fromDate).And(toDate)
    .SelectGroup(x => x.CreatedBy.Id);

var results = Session.QueryOver<Person>()
    .WithSubquery.WhereProperty(x => x.Id).NotIn(peopleWithOrdersInRange)
    .List();

this will produce that exact SQL (with addition of group by people id in the subquery)

OTHER TIPS

When I query with the solution provided in the above question, it fails if there are 2100 people or more (SQL won't allow that many parameters).

As I understand you do materialize persons with orders collection before passing it into a query.

Here is a linq query that should work

var unwantedPersons = 
   from order in session.Query<Order>()
   where order.CreatedDate >= startDate && 
         order.CreatedDate <= endDate
   select order.CreatedBy.Id // NOTE: do not add .ToList() or .ToArray() here.
                             // It *should be* IQueryable<Person> 

var personsWitoutOrders = 
    (from person in session.Query<Person>()
     where !unwantedPersons.Contains(person.Id)
     select person).ToArray();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top