How do I express a query containing a WHERE..IN subquery using NHibernate's QueryOver API?

北战南征 提交于 2019-12-11 09:32:35

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!