views:

676

answers:

3

If I have Order entity with a list of OrderDetails I can easily eager load the detail along with the order by using NHibernateUtil.Initialize(Order.Details). So obviously the NHibernate have all the information to generate the sql statement. But how do I query the database for just the Details (similar to CreateSourceQuery in Entity Framework) without manually creating a criteria? Is there something like NHibernateUtil.GetList(Order.Details)?

Update: Using Darin's answer this what I finally ended up with. This is generic enough i can implement it in entity base class

Dim entity as EntityBase
Dim queryString = String.Format("select entityAlias.{1} from {0} entityAlias where entityAlias.id = :ID", entity.GetType.Name, collectionPropertyName)
Dim query = Session.CreateQuery(queryString).SetParameter("ID", entity.ID)
Return query.List
+1  A: 

The recommended way of querying objects in NHibernate is using either the Criteria API or HQL. Do you have any reason against any of these two approaches?

var details = session.CreateCriteria<OrderDetails>().List<OrderDetails>();
var details = session.CreateQuery("from OrderDetails").List<OrderDetails>();


UPDATE:

If you want to load only the association without loading the parent object you could use the following query:

var details = session.CreateQuery(
        "select " + 
        "  orderDetail" + 
        "from " + 
        "  Order order," + 
        "  OrderDetail orderDetail " + 
        "where " + 
        "  orderDetail in elements(order.Details)"
    )
    .List<OrderDetail>();
Darin Dimitrov
I want to be able to create a generic method that will take an Entity, and it's association path, and return the associated list (in this case OrderDetails). using createCriteria i would have to specify the restriction Order.ID = xx. I figure NHibernate already have this information and I was wondering if there's an equivalent of Entity Framework's CreateSourceQuery method.
Olonarp
Once you get an instance of `Order`, you just use the association `order.OrderDetails` to get the details.
Darin Dimitrov
Thanks Darin. I think I can use this.
Olonarp
+1  A: 

Why not just load the Order and access its Details collection? If you were able to just load the collection, you would not be able to add to the collection because an Order is required for the relationship.

I think you are misusing NHibernateUtil.Initialize. Its purpose is to force initialization of a proxy collection (lazy loaded) in special cases. Eager loading is the opposite of lazy-loading; in that scenario the collection would always be loaded with its parent object and there would be no need for a proxy. If you already have the Order object then accessing the Details collection will cause it to be loaded. If you want eager fetch you can set that in the mapping options.

Jamie Ide
I was just using NHibernateUtil.Initialize to illustrate the kind of query I need. In my case I already loaded Order and the associated Details, but there will be changes made that require me to reload Details. I can easily create a criteria reloading both Order and Details (using SetFetchMode), but I need a way to get just Details. I was hoping there's already a function or trivial way to get this without recreating information NHibernate already have internally.
Olonarp
Can you expand on why you need to re-load Details? If you need to pick up database changes, such as trigger actions, you can call ISession.Refresh() or reload Order in a new ISession.
Jamie Ide
Yes there are changes caused by the trigger. What I am trying to do is get only the details, since in this case I know those are the only changes, and then merge it back to Order.Details manually. Refresh or Reloading order in another session would be doing superfluous data fetching (it loads order and other unchanged association), since in this special case only details is changed.
Olonarp
+1  A: 

NHibernate has a built in method to do exactly what I think you are asking. (ISession.CreateFilter)

For example if you have a Customer entity loaded named customer which has a collection of Orders named Orders, you can load the orders by doing this.

var orderQuery = session.CreateFilter(customer.Orders, string.Empty);  
var orders = orderQuery.List<Order>();

This is equivilant to the following, just a little cleaner.

var orderQuery = session.CreateQuery("from orders o where o.Customer.id = :customerId")
                        .SetParameter("customerId", customer.Id);
var orders = orderQuery.List<Order>();

If you want to filter the collection, an hql where clause can be passed as the second argument to ISession.CreateFilter(object, string)

I Am The Enterprise
Thank you. This is exactly what I was looking for. I never thought of using filter. I actually have been doing the query (your second example).
Olonarp