在关系模型中:可以使用子表作为内连接查询Customer,像这样:

select * from Customer c inner join Order o on c.CustomerId=o.CustomerId where o.CustomerId=<id of the Customer>

使用父表作为内连接查询Order,像这样:

select * from Oder o inner join Customer c on o.CustomerId=c.CustomerId where o.OrderId=<id of the Order>

下面我们来看看在NHibernate中使用原生SQL查询。这篇来完成查询订单在orderData之后的顾客列表不同查询的写法。

public IList<Customer> UseSQL_GetCustomersWithOrders(DateTime orderDate)
    return _session.CreateSQLQuery("select distinct {customer.*} from Customer {customer}"+
    " inner join [Order] o on o.Customer={customer}.CustomerId where o.OrderDate> :orderDate")
        .AddEntity("customer", typeof(Customer))
        .SetDateTime("orderDate", orderDate)
        .List<Customer>();

2.HQL关联查询

查询订单在orderData之后的顾客列表的HQL关联查询写法:

public IList<Customer> UseHQL_GetCustomersWithOrders(DateTime orderDate)
    return _session.CreateQuery("select distinct c from Customer c inner join c.Orders o  where o.OrderDate > :orderDate")
        .SetDateTime("orderDate", orderDate)
        .List<Customer>();

这里使用基于面向对象的HQL,一目了然,符合面向对象编程习惯。

3.Criteria API关联查询

我们使用CreateCriteria()在关联之间导航,很容易地在实体之间指定约束。这里第二个CreateCriteria()返回一个ICriteria的新实例,并指向Orders实体的元素。在查询中子对象使用子CreateCriteria语句,这是因为实体之间的关联我们在映射文件中已经定义好了。还有一种方法使用CreateAlias()不会创建ICriteria的新实例。

这个例子返回顾客列表有重复的,不是我们想要的结果。

public IList<Customer> UseCriteriaAPI_GetCustomersWithOrders(DateTime orderDate)
    return _session.CreateCriteria(typeof(Customer))
        .CreateCriteria("Orders")
        .Add(Restrictions.Gt("OrderDate", orderDate))
        .List<Customer>();

使用ICriteria接口的SetResultTransformer(IResultTransformer resultTransformer)方法返回满足特定条件的Customer。上面例子中使用条件查询,观察其生成的SQL语句并没有distinct,这时可以使用NHibernate.Transform命名空间中的方法或者使用NHibernate提供的NHibernate.CriteriaUtil.RootEntity、NHibernate.CriteriaUtil.DistinctRootEntity、NHibernate.CriteriaUtil.AliasToEntityMap静态方法实现预过滤的作用。那么上面的查询应该修改为:

public IList<Customer> UseCriteriaAPI_GetCustomersWithOrders(DateTime orderDate)
    return _session.CreateCriteria(typeof(Customer))
        .CreateCriteria("Orders")
        .Add(Restrictions.Gt("OrderDate", orderDate))
        .SetResultTransformer(new NHibernate.Transform.DistinctRootEntityResultTransformer())
        //或者.SetResultTransformer(NHibernate.CriteriaUtil.DistinctRootEntity)
        .List<Customer>();

这个例子从转换结果集的角度实现了我们想要的效果。

many-to-many:

1.原生SQL关联查询

public IList<Customer> UseSQL_GetCustomersWithOrdersHavingProduct(DateTime orderDate)
    return _session.CreateSQLQuery("select distinct {customer.*} from Customer {customer}" +
    " inner join [Order] o on o.Customer={customer}.CustomerId"+
    " inner join OrderProduct op on o.OrderId=op.[Order]"+
    " inner join Product p on op.Product=p.ProductId where o.OrderDate> :orderDate")
        .AddEntity("customer", typeof(Customer))
        .SetDateTime("orderDate", orderDate)
        .List<Customer>();

这里需要使用Join告诉查询如何在表之间关联。无论多么复杂的关系,我们必须在查询语句中指定返回值。这里使用AddEntity设置返回的实体。

2.HQL关联查询

public IList<Customer> UseHQL_GetCustomersWithOrdersHavingProduct(DateTime orderDate)
    return _session.CreateQuery("select distinct c from Customer c ,"
        + " c.Orders.elements o where o.OrderDate > :orderDate")
        .SetDateTime("orderDate", orderDate)
        .List<Customer>();

因为在映射文件已经定义实体之间一对多、多对多关系,NHibernate通过映射文件知道如何去关联这些实体,我们不需要在查询语句中重复定义。这里使用查询和上一篇使用HQL关联查询语句一样,NHibernate完全可以去关联对象,实现查询订单和产品。

3.Criteria API关联查询

因为实体之间的关联我们在映射文件中已经定义好了。所以我们在查询子对象使用子CreateCriteria语句关联对象之间导航,可以很容易地在实体之间指定约束。这里第二个CreateCriteria()返回ICriteria的新实例,并指向Orders实体的元素。第三个指向Products实体的元素。

public IList<Customer> UseCriteriaAPI_GetCustomerswithOrdersHavingProduct()
    return _session.CreateCriteria(typeof(Customer))
        .Add(Restrictions.Eq("Firstname","YJing"))
        .CreateCriteria("Orders")
        .Add(Restrictions.Gt("OrderDate",new DateTime(2008,10,1)))
        .CreateCriteria("Products")
        .Add(Restrictions.Eq("Name","Cnblogs"))
        .List<Customer>();