Reload association/related collection in NHibernat

2019-04-03 01:09发布

问题:

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:

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)



回答2:

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.



回答3:

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>();