Mapping with ConfORM
ConfORM映射
ConfORM项目使得NHibernate可以使用基于约定的映射.本节将介绍使用ConfORM约定来映射的你的模型(实体类).
准备工作:
1. 从Google代码:http://code.google.com/p/codeconform/source/checkout 签出ConfORM源代码
2. 编译ConfORM项目.
3. 完成前面和Eg.Core相关的模型和映射的章节.
如何去做:
1. 创建一个新的名为Eg.ConfORMMappings控制台项目.
2. 添加对Eg.Core项目以及ConfORM.dll和ConfORM.Shop.dll的引用.
3. 在Eg.Core.Entity中, 更改属性Version的修饰符为public
4. 在Program.cs, 在文件头部添加下列using 语句:
View Code
using System; using System.IO; using System.Linq; using System.Xml; using System.Xml.Serialization; using ConfOrm; using ConfOrm.NH; using ConfOrm.Patterns; using ConfOrm.Shop.CoolNaming; using Eg.Core; using NHibernate; using NHibernate.Cfg.MappingSchema;
5. 在Program类中添加下述的GetMapping函数:
View Code
private static HbmMapping GetMapping() { var orm = new ObjectRelationalMapper(); var mapper = new Mapper(orm, new CoolPatternsAppliersHolder(orm)); orm.TablePerClassHierarchy<Product>(); orm.TablePerClass<ActorRole>(); orm.Patterns.PoidStrategies.Add( new GuidOptimizedPoidPattern()); orm.VersionProperty<Entity>(x => x.Version); orm.NaturalId<Product>(p => p.Name); orm.Cascade<Movie, ActorRole>( Cascade.All | Cascade.DeleteOrphans); mapper.AddPropertyPattern(mi => mi.GetPropertyOrFieldType() == typeof(Decimal) && mi.Name.Contains("Price"), pm => pm.Type(NHibernateUtil.Currency)); mapper.AddPropertyPattern(mi => orm.IsRootEntity(mi.DeclaringType) && !"Description".Equals(mi.Name), pm => pm.NotNullable(true)); mapper.Subclass<Movie>(cm => cm.List(movie => movie.Actors, colm => colm.Index( lim => lim.Column("ActorIndex")), m => { })); var domainClasses = typeof(Entity).Assembly.GetTypes() .Where(t => typeof(Entity).IsAssignableFrom(t)); return mapper.CompileMappingFor(domainClasses); }
6. 添加下述WriteXmlMapping函数:
View Code
private static void WriteXmlMapping(HbmMapping hbmMapping) { var document = Serialize(hbmMapping); File.WriteAllText("WholeDomain.hbm.xml", document); }
7. 添加下述Serialize函数:
View Code
private static string Serialize(HbmMapping hbmElement) { var setting = new XmlWriterSettings { Indent = true }; var serializer = new XmlSerializer(typeof(HbmMapping)); using (var memStream = new MemoryStream(2048)) using (var xmlWriter = XmlWriter.Create(memStream, setting)) { serializer.Serialize(xmlWriter, hbmElement); memStream.Flush(); memStream.Position = 0; using (var sr = new StreamReader(memStream)) { return sr.ReadToEnd(); } } }
8. 在static void Main 方法中, 添加一行代码:
WriteXmlMapping(GetMapping());
9. 编译运行该程序
10. 查找该程序的bin\Debug文件夹,打开WholeDomain.hbm.xml文件,将会看到下述映射:
View Code
<?xml version="1.0" encoding="utf-8"?> <hibernate-mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" namespace="Eg.Core" assembly="Eg.Core" xmlns="urn:nhibernate-mapping-2.2"> <class name="Product"> <id name="Id" type="Guid"> <generator class="guid.comb" /> </id> <discriminator /> <natural-id> <property name="Name" not-null="true" /> </natural-id> <version name="Version" /> <property name="Description" /> <property name="UnitPrice" type="Currency" not-null="true" /> </class> <class name="ActorRole"> <id name="Id" type="Guid"> <generator class="guid.comb" /> </id> <version name="Version" /> <property name="Actor" not-null="true" /> <property name="Role" not-null="true" /> </class> <subclass name="Book" extends="Product"> <property name="ISBN" /> <property name="Author" /> </subclass> <subclass name="Movie" extends="Product"> <property name="Director" /> <list name="Actors" cascade="all,delete-orphan"> <key column="MovieId" /> <list-index column="ActorIndex" /> <one-to-many class="ActorRole" /> </list> </subclass> </hibernate-mapping>
分析原理:
标准的NHibernate应用程序中,NHibernate会获取所有的XML映射文件,并将其串行化到一个HbmMapping对象中,然后将这个HbmMapping对象添加到NHibernate设置中,如下图所示:

使用ConfORM, 我们就跳过了串行化的步骤,ConfORM映射器可以由我们的约定生成一个HbmMapping对象,该对象将被添加到配置中.
ConfORM使用约定和模式可以从Model直接生成一个映射.除了使用ConfORM的默认模式, 我们还可以自定义约定.
1. 我们先是指定了Product类的层级,她包含Books和Movies类. 然后我们单独添加了ActorRole实体类.
2. 我们使用GuidOptimizedPoidPattern查找到所有名为Id的Guid属性,并使用guid.comb生成器将他们映射为POIDs.
3. 添加从Movie到ActorRole的引用,比如我们的Actors集合,应该用cascade="all-delete-orphan".我们使用下述代码以完成该设置:
orm.Cascade<Movie, ActorRole>(
Cascade.All | Cascade.DeleteOrphans);
4. 然后,我们配置一些约定.在属性名中所有名为Price的decimal属性都应映射为: type="currency".使用下述代码:
mapper.AddPropertyPattern(mi => mi.GetPropertyOrFieldType() == typeof(Decimal) && mi.Name.Contains("Price"), pm => pm.Type(NHibernateUtil.Currency));
5. 在根类型的实体类的属性中,除了Description属性,她们的映射都使用了not-null="true" .请注意,我们使用的是table-per-class映射方式, 所以我们subclasses 不能包含not-null="true"属性. 代码如下:
View Code
mapper.AddPropertyPattern(mi => orm.IsRootEntity(mi.DeclaringType) && !"Description".Equals(mi.Name), pm => pm.NotNullable(true));
6. 最后,映射Movies中的Actors列表,将该列的索引列名设置为ActorIndex代码如下:
View Code
mapper.Subclass<Movie>(cm => cm.List(movie => movie.Actors, colm => colm.Index( lim => lim.Column("ActorIndex")), m => { }));
7. 生成HbmMapping对象的最后一步是通过每一个实体的类型调用CompileMappingFor.代码如下:
View Code
var domainClasses = typeof(Entity).Assembly.GetTypes() .Where(t => typeof(Entity).IsAssignableFrom(t)); return mapper.CompileMappingFor(domainClasses);
8. 所生成的的mapping对象和XML映射文件:WholeDomain.hbm.xml所包含的内容是等价的.


浙公网安备 33010602011771号