问题
I have an object model where an Order
contains many LineItems
, and each LineItem
has an associated Product
. In the object model, these are one-way associations -- a LineItem
does not know anything about its Order
.
I want to query for orders that contain a line item with a product name matching a string, returning one row for each order (so that paging can be performed).
SELECT * FROM Orders
WHERE OrderID IN (
SELECT DISTINCT OrderID
FROM LineItems
INNER JOIN Products on LineItems.ProductID = Products.ProductID
WHERE Products.Name = 'foo'
)
Given that I have an ICriteria
or an IQueryOver
representing the subquery, how do I actually apply it to my root Order query?
var subquery = QueryOver.Of<LineItem>
.Where(l => l.Product.Name == "foo")
.TransformUsing(Transformers.DistinctRootEntity);
I've found plenty of examples that assume the root object in the query is on the "many" side of a one-to-many relationship, but I can't figure out how to add a restriction on something that the root object has many of.
回答1:
I'd make it a bi-directional relationship between order and line item to allow efficient queries (reduce the number of joins required). But, if for some weird reason you can't, you'll need to start the sub-query from the Order...
LineItem lineItemAlias = null;
Product productAlias = null;
var subQuery = QueryOver.Of<Order>()
.JoinAlias(x => x.LineItems, () => lineItemAlias)
.JoinAlias(() => lineItemAlias.Product, () => productAlias)
.Where(() => productAlias.Name == "foo")
.Select(Projections.Group<Order>(x => x.Id));
var results = Session.QueryOver<Order>()
.WithSubquery.WhereProperty(x => x.Id).In(subQuery)
.List();
回答2:
The direct translation of the SQL that you provided can be acheived using this
var subQuery =
QueryOver.Of<LineItem>(() => lineItem)
.JoinAlias(() => lineItem.Products, () => product)
.Where(() => product.Name == "foo")
.Select(Projections.Distinct(
Projections.Property(()=> lineItem.Order.Id)));;
var theQueryYouNeed =
QueryOver.Of<Orders>(() => order)
.WithSubquery.WherePropertyIn(() => order.Id).In(subQuery);
However if your LineItem
entity does not have a Order
Property then you cannot really use the subquery.
If you need to find
All Orders which have a LineItem where the Product Name is "foo" then
var theQueryYouNeed =
QueryOver.Of<Orders>(() => order)
.JoinAlias(() => order.LineItems, () => lineItem)
.JoinAlias(() => lineItem.Product, () => product)
.Where(() => product.Name == "foo")
.TransformUsing(new DistinctRootEntityResultTransformer())
来源:https://stackoverflow.com/questions/13995272/how-do-i-express-a-query-containing-a-where-in-subquery-using-nhibernates-quer