To explain my problem more easily I will create the following fictional example, illustrating a very basic many-to-many relationship. A Car can have many Parts, and a Part can belong to many Cars.
DB SCHEMA:
CAR_TABLE
---------
CarId
ModelName
CAR_PARTS_TABLE
---------------
CarId
PartId
PARTS_TABLE
-----------
PartId
PartName
CLASSES:
public class Car
{
public int CarId {get;set;}
public string Name {get;set;}
public IEnumerable<Part> Parts {get;set;}
}
public class Part
{
public int PartId {get;set;}
public string Name {get;set}
}
Using this very simple model I would like to get any cars that have all the parts assigned to them from a list of parts I am searching on.
So say I have an array of PartIds:
var partIds = new [] { 1, 3, 10};
I want to mimic the following c# code in terms of a database call:
var allCars = /* code to retrieve all cars */
var results = new List<Car>();
foreach (var car in allCars)
{
var containsAllParts = true;
foreach (var carPart in car.Parts)
{
if (false == partIds.Contains(carPart.PartId))
{
containsAllParts = false;
break;
}
}
if (containsAllParts)
{
results.Add(car);
}
}
return results;
To be clear: I want to get the Cars that have ALL of the Parts specified from the partIds array.
I have the following query, which is REALLY inefficient as it creates a subquery for each id within the partIds array and then does an IsIn query on each of their results. I am desperate to find a much more efficient manner to execute this query.
Car carAlias = null;
Part partAlias = null;
var searchCriteria = session.QueryOver<Car>(() => carAlias);
foreach (var partId in partIds)
{
var carsWithPartCriteria = QueryOver.Of<Car>(() => carAlias)
.JoinAlias(() => carAlias.Parts, () => partAlias)
.Where(() => partAlias.PartId == partId)
.Select(Projections.Distinct(Projections.Id()));
searchCriteria = searchCriteria
.And(Subqueries.WhereProperty(() => carAlias.Id).In(carsWithPartCriteria));
}
var results = searchCriteria.List<Car>();
Is there a decent way to execute this sort of query using NHibernate?
This should be exactly what you want…