NHibernate教程(11)--多对多关联查询

本节内容

  • 多对多关系引入
  • 多对多映射关系
  • 多对多关联查询
    • 1.原生SQL关联查询
    • 2.HQL关联查询
    • 3.Criteria API关联查询
  • 结语

多对多关系引入

让我们再次回顾在第二篇中建立的数据模型:

数据关系模型

在图上,我已经清晰的标注了表之间的关系,上两篇分析Customer和Order之间的“外键关系”或者称作“父子关系”、“一对多关系”和关联查询,这一篇以Order为中心,分析Order和Product之间的关系,直接看下面一幅图的两张表:

多对多关系

上面两张表关系表达的意思是:Order有多个Products,Product属于多个Orders。我们称Order和Product是多对多关系,这一篇我们来深入讨论在NHibernate如何映射多对多关系及其多对多关联查询。

多对多映射关系

1.Order有多个Products

有了上两篇的基础,现在直奔主题,建立关系。大家可以把这篇的代码作为模板,以后在工作中参考。

修改Order.cs类代码如下:

namespace DomainModel.Entities
{
    public class Order
    {
        public virtual int OrderId { get; set; } public virtual DateTime OrderDate { get; set; } //多对一关系:Orders属于一个Customer public virtual Customer Customer { get; set; } //多对多关系:Order有多个Products public virtual IList<Product> Products { get; set; } } }

修改Order.hbm.xml映射文件如下:

<?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="DomainModel" namespace="DomainModel"> <class name="DomainModel.Entities.Order,DomainModel" table="`Order`" > <id name="OrderId" column="OrderId" type="Int32" unsaved-value="0"> <generator class="native" /> </id> <property name="OrderDate" column="OrderDate" type="DateTime" not-null="true" /> <!--多对一关系:Orders属于一个Customer--> <many-to-one name="Customer" column="Customer" not-null="true" class="DomainModel.Entities.Customer,DomainModel" foreign-key="FK_CustomerOrders" /> <!--多对多关系:Order有多个Products--> <bag name="Products" generic="true" table="OrderProduct"> <key column="`Order`" foreign-key="FK_OrderProducts"/> <many-to-many column="Product" class ="DomainModel.Entities.Product,DomainModel" foreign-key="FK_ProductOrders"/> </bag> </class> </hibernate-mapping>

在多对多关系中,其两方都使用Bag集合和many-to-many元素。看看上面各个属性和one-to-many,many-to-one属性差不多。

2.Product属于多个Orders

在项目DomainModel层的Entities文件夹中新建Product.cs类,编写代码如下:

namespace DomainModel.Entities
{
    public class Product
    {
        public virtual int ProductId { get; set; } public virtual string Name { get; set; } public virtual float Cost { get; set; } //多对多关系:Product属于多个Orders public virtual IList<Order> Orders { get; set; } } }

在项目DomainModel层的Mappings文件夹中新建Product.hbm.xml映射文件,编写代码如下:

<?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="DomainModel" namespace="DomainModel"> <class name="DomainModel.Entities.Product,DomainModel" table="Product"> <id name="ProductId" column ="ProductId" type="Int32" unsaved-value="0"> <generator class="native"/> </id> <property name="Name" column="Name" type="string" not-null="true" length="50"/> <property name="Cost" column="Cost" type="float" not-null="true"/> <!--多对多关系:Product属于多个Orders--> <bag name="Orders" generic="true" table="OrderProduct"> <key column="Product" foreign-key="FK_ProductOrders"/> <many-to-many column="`Order`" class="DomainModel.Entities.Order,DomainModel" foreign-key="FK_OrderProducts"/> </bag> </class> </hibernate-mapping>

多对多关联查询

使用NHibernate中提供的三种查询方法实现多对多关联查询,查询返回所有订单和产品的顾客列表。

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

下面我用一幅图简单明了的说明这段代码神秘之处,也显示了一些约束条件。

条件查询

编写一个测试用例测试UseCriteriaAPI_GetCustomerswithOrdersHavingProduct()方法,遍历列表,看看产品名称是否为“Cnblogs”,OK!测试通过。

[Test]
public void UseCriteriaAPI_GetCustomerswithOrdersHavingProductTest()
{
    IList<Customer> customers = _relation.UseCriteriaAPI_GetCustomerswithOrdersHavingProduct();
    bool found = false; foreach (Customer c in customers) { foreach (Order o in c.Orders) { foreach (Product p in o.Products) { if (p.Name == "Cnblogs") { found = true; break; } } } } Assert.IsTrue(found); }

下面再写个简单例子查询产品Id所关联的一些顾客,测试用例同上面差不多,自己修改下就可以啦。

public IList<Customer> UseCriteriaAPI_GetCustomerswithOrdersHavingProduct(int productId)
{
    return _session.CreateCriteria(typeof(Customer)) .CreateCriteria("Orders") .CreateCriteria("Products") .Add(Restrictions.Eq("ProductId", productId)) .List<Customer>(); }

结语

这一篇通过全盘代码的形式完成NHibernate中的多对多关系映射,使用NHibernate中提供的三种查询方法实现了多对多关联查询。希望对你有所帮助,多多练习。我们下次继续讨论NHibernate话题,像延迟加载、立即加载、对象状态等话题,关于朋友回复说讨论更多话题,我只能说,再等等吧,慢慢来,这才第十一篇,先把基础的问题弄清楚。

本系列链接:NHibernate之旅系列文章导航

NHibernate Q&A

下次继续分享NHibernate!

转载于:https://www.cnblogs.com/zhengwei-cq/p/7381083.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值