摘要
NHibernate的多对多关系映射由many-to-many定义。
从这里下载本文的代码NHibernate Demo
1、修改数据库
添加Product表
添加ProductOrder表
数据库表之间的关系:
Product和Order之间的关系是多对多关系,一条订单上有多个产品,一个产品可以有多个订单。多对多关系中的中间表(这里是ProductOrder表)不需要在关系映射中定义实体类和映射文件。
实际项目中,Product和Order之间应该不是这种简单的多对多关系,而是有个“订单明细”的表OrderDetail,记录了明细记录里产品的数量,单价等信息。如下图:
OrderDetail表:
数据库表之间的关系:
Order和OrderDetail之间,以及Product和OrderDetail之间是两个一对多关系。
作为示例,使用ProductOrder表演示怎么实现多对多关系映射。
实际项目中,角色和用户之间的关系就是典型的多对多关系。
2、修改实体类文件
添加Product类
1 using System.Collections.Generic; 2 3 namespace Demo.XML.Entities.Domain 4 { 5 public class Product 6 { 7 public Product() 8 { 9 Orders = new List<Order>(); 10 } 11 12 public virtual int Id { get; set; } 13 14 public virtual string ProductCode { get; set; } 15 16 public virtual string ProductName { get; set; } 17 18 public virtual string Description { get; set; } 19 20 public virtual IList<Order> Orders { get; set; } 21 } 22 }
修改Order类
1 using System; 2 using System.Collections.Generic; 3 4 namespace Demo.XML.Entities.Domain 5 { 6 public class Order 7 { 8 public Order() 9 { 10 Products = new List<Product>(); 11 } 12 public virtual int Id { get; set; } 13 public virtual DateTime Ordered { get; set; } 14 public virtual DateTime? Shipped { get; set; } 15 public virtual Address ShipTo { get; set; } 16 public virtual Customer Customer { get; set; } 17 public virtual IList<Product> Products { get; set; } 18 } 19 }
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函数
1 static void Main(string[] args) 2 { 3 HibernatingRhinos.Profiler.Appender.NHibernate.NHibernateProfiler.Initialize(); 4 5 var product = new Product 6 { 7 ProductName = "apple", 8 ProductCode = "1111", 9 Orders = new List<Order> 10 { 11 new Order { 12 Ordered = DateTime.Now 13 } 14 } 15 }; 16 productService.Save(product); 17 18 Console.WriteLine("Completed"); 19 Console.ReadLine(); 20 }
执行程序,得到类似下图的监控结果。
读者可以自己尝试添加Order对象。
删除和修改请读者自己尝试吧,贴代码和图片太繁琐了。