NHibernate系列文章十九:NHibernate关系之多对多关系(附程序下载)

时间:2023-03-09 01:22:52
NHibernate系列文章十九:NHibernate关系之多对多关系(附程序下载)

摘要

NHibernate的多对多关系映射由many-to-many定义。

从这里下载本文的代码NHibernate Demo

1、修改数据库

添加Product表

NHibernate系列文章十九:NHibernate关系之多对多关系(附程序下载)

添加ProductOrder表

NHibernate系列文章十九:NHibernate关系之多对多关系(附程序下载)

数据库表之间的关系:

NHibernate系列文章十九:NHibernate关系之多对多关系(附程序下载)

Product和Order之间的关系是多对多关系,一条订单上有多个产品,一个产品可以有多个订单。多对多关系中的中间表(这里是ProductOrder表)不需要在关系映射中定义实体类和映射文件。

实际项目中,Product和Order之间应该不是这种简单的多对多关系,而是有个“订单明细”的表OrderDetail,记录了明细记录里产品的数量,单价等信息。如下图:

OrderDetail表:

NHibernate系列文章十九:NHibernate关系之多对多关系(附程序下载)

数据库表之间的关系:

NHibernate系列文章十九:NHibernate关系之多对多关系(附程序下载)

Order和OrderDetail之间,以及Product和OrderDetail之间是两个一对多关系。

作为示例,使用ProductOrder表演示怎么实现多对多关系映射。

实际项目中,角色和用户之间的关系就是典型的多对多关系。

2、修改实体类文件

添加Product类

 using System.Collections.Generic;

 namespace Demo.XML.Entities.Domain
{
public class Product
{
public Product()
{
Orders = new List<Order>();
} public virtual int Id { get; set; } public virtual string ProductCode { get; set; } public virtual string ProductName { get; set; } public virtual string Description { get; set; } public virtual IList<Order> Orders { get; set; }
}
}

修改Order类

 using System;
using System.Collections.Generic; namespace Demo.XML.Entities.Domain
{
public class Order
{
public Order()
{
Products = new List<Product>();
}
public virtual int Id { get; set; }
public virtual DateTime Ordered { get; set; }
public virtual DateTime? Shipped { get; set; }
public virtual Address ShipTo { get; set; }
public virtual Customer Customer { get; set; }
public virtual IList<Product> Products { get; set; }
}
}

3、修改映射文件

添加Product.hbm.xml

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Demo.XML.Entities" namespace="Demo.XML.Entities.Domain">
<class name="Product" table="Product">
<id name="Id">
<generator class="native"/>
</id>
<property name="ProductCode" not-null="true"/>
<property name="ProductName" not-null="true"/>
<property name="Description"/>
<bag name="Orders" table="ProductOrder" cascade="all">
<key column="ProductId"/>
<many-to-many class="Order" column="OrderId"/>
</bag>
</class>
</hibernate-mapping>

修改Order.hbm.xml文件

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Demo.XML.Entities" namespace="Demo.XML.Entities.Domain">
<class name="Order" table="`Order`">
<id name="Id">
<generator class="native"/>
</id>
<property name="Ordered"/>
<property name="Shipped"/>
<component name="ShipTo">
<property name="Street"/>
<property name="City"/>
<property name="Province"/>
<property name="Country"/>
</component>
<many-to-one name="Customer" column="CustomerId" cascade="save-update"/>
<bag name="Products" table="ProductOrder" cascade="all">
<key column="OrderId"/>
<many-to-many class="Product" column="ProductId"/>
</bag>
</class>
</hibernate-mapping>

注意:Product和Order两边都设置了cascade="all"。这样,不管从哪边Product或者Order对数据进行添加、修改、删除都能够进行级联更新。

因为是用IList作为级联属性的类型,所以在映射文件里用Bag属性。

这里同样的是使用了双向关联。两个映射文件的Bag属性内容刚好是“对称性”的。

4、添加接口IProductService和类ProductService,修改Program.cs文件

在Program类添加静态属性productService。

static readonly IProductService productService = new ProductService();

修改Main函数

         static void Main(string[] args)
{
HibernatingRhinos.Profiler.Appender.NHibernate.NHibernateProfiler.Initialize(); var product = new Product
{
ProductName = "apple",
ProductCode = "",
Orders = new List<Order>
{
new Order {
Ordered = DateTime.Now
}
}
};
productService.Save(product); Console.WriteLine("Completed");
Console.ReadLine();
}

执行程序,得到类似下图的监控结果。

NHibernate系列文章十九:NHibernate关系之多对多关系(附程序下载)

读者可以自己尝试添加Order对象。

删除和修改请读者自己尝试吧,贴代码和图片太繁琐了。