NHibernate剖析:Mapping篇之ModelMapper实战(2):运用ModelMapper

本节内容
  • ModelMapper概览
  • 运用ModelMapper
  • 结语
  • 参考资料

ModelMapper概览

上一篇文章介绍了Mapping-By-Code(代码映射)的原理,这篇文章结合上篇的原理运用Mapping-By-Code(代码映射)。为了更有效的学习代码映射,这篇文章使用单元测试的方式,每一个测试用例代表某一功能实现,并且为了 直观的认识HbmMapping对象,我把HbmMapping对象序列化为字符串写入标准输出流,为此定义一个名为ShowInConsole的扩展方法。
public static class HbmMappingExtensions { public static void ShowInConsole(this HbmMapping mapping) { Console.WriteLine(mapping.AsString()); } }

运用ModelMapper

我们先定义一个非常简单的Domain模型,一个int类型的Id属性和一个string类型的Something属性,用来代码映射:
public class MyClass { public int Id { get; set; } public string Something { get; set; } }

1.基本映射

ModelMapper提供一种基本映射方式:使用Class方法对实体类MyClass特定映射:
  • 属性Id映射为数据库主键,对应的列名称为MyClassId、主键生成策略是HighLow策略。
  • 属性Something映射为数据库普通字段,其长度为150。
最后调用CompileMappingForAllExplicitAddedEntities方法显式所有映射的实体(这里是MyClass)编译为HbmMapping对象并输出,也可以使用CompileMappingFor方法指定实体类型。
[Test] public void BasicMappingRegistration() { var mapper = new ModelMapper(); mapper.Class(cm => { cm.Id(myclass => myclass.Id, map => { map.Column("MyClassId"); map.Generator(Generators.HighLow); }); cm.Property(myclass => myclass.Something, map => map.Length(150)); }); var hbmMapping = mapper.CompileMappingForAllExplicitAddedEntities(); //var hbmMapping = mapper.CompileMappingFor(new[] {typeof (MyClass)}); hbmMapping.ShowInConsole(); }
NHibernate对于代码映射提供很强的灵活性,你可以像你希望的那样随意去组织映射:例如class-by-class方式、不同的映射点在不同的地方等等。
例如下面代码映射,分开去配置映射,NHibernate对重复的属性不重复映射,去合并映射:
[Test] public void WhenDuplicatePropertiesDoesNotDuplicateMapping() { var mapper = new ModelMapper(); mapper.Class(cm => { cm.Id(myclass => myclass.Id, map => map.Column("MyClassId")); cm.Id(myclass => myclass.Id, map => map.Generator(Generators.HighLow)); cm.Property(myclass => myclass.Something); cm.Property(myclass => myclass.Something, map => map.Length(150)); }); var hbmMapping = mapper.CompileMappingForAllExplicitAddedEntities(); hbmMapping.ShowInConsole(); }
你甚至也可以在两个不同地方去映射整个实体类:
[Test] public void WhenDuplicateClassDoesNotDuplicateMapping() { var mapper = new ModelMapper(); mapper.Class(cm => { cm.Id(myclass => myclass.Id, map => map.Generator(Generators.HighLow)); cm.Property(myclass => myclass.Something); }); mapper.Class(cm => { cm.Id(myclass => myclass.Id, map => map.Column("MyClassId")); cm.Property(myclass => myclass.Something, map => map.Length(150)); }); var hbmMapping = mapper.CompileMappingForAllExplicitAddedEntities(); hbmMapping.ShowInConsole(); }

2.Conformist映射

ModelMapper提供另外一种Conformist映射方式:class-by-class方式,即每个类定义一个类去映射,然后调用AddMapping方法把映射加入ModelMapper对象。
private class MyClassMap : ClassMapping { public MyClassMap() { Id(myclass => myclass.Id, map => { map.Column("MyClassId"); map.Generator(Generators.HighLow); }); Property(myclass => myclass.Something, map => map.Length(150)); } } [Test] public void ConformistMappingRegistration() { var mapper = new ModelMapper(); mapper.AddMapping(); var hbmMapping = mapper.CompileMappingForAllExplicitAddedEntities(); hbmMapping.ShowInConsole(); }
上面的映射如果查看其输出结果,都是一样:
SimpleClassMappingNHibernate剖析:Mapping篇之ModelMapper实战(2):运用ModelMapper

3.约定

ModelMapper提供了很多事件监听器,可以通过它扩展ModelMapper。其中就是自定义约定。其实上面定义的映射从设计思想上面说也是一种约定,暂时可以称作特定约定(Specific-Convetions)
以Before开头的事件监听称作前置约定(Pre-Conventions)。从人性化角度看前置约定(Pre-Conventions)比较民主(democratic),我们映射时可以使用特定约定(Specific-Convetions)
以After开头的事件监听称作后置约定(Post-Conventions)或者称作Hard-Conventions。从人性化角度看后置约定(Post-Conventions)就比较共和(republican),不管前面怎么特定,到最后一律使用后置约定(Post-Conventions)所规定的"条约"。
例如下面例子使用前置约定(Pre-Conventions):
[Test] public void MapClassWithConventions() { var mapper = new ModelMapper(); //option:Pre-Conventions mapper.BeforeMapClass += (mi, t, map) => map.Id(x => x.Column((t.Name + "id").ToUpper())); mapper.BeforeMapProperty += (mi, propertyPath, map) => map.Column(propertyPath.ToColumnName().ToUpper()); mapper.Class(cm => { cm.Id(myclass => myclass.Id, map => map.Generator(Generators.HighLow)); cm.Property(myclass => myclass.Something); }); var hbmMapping = mapper.CompileMappingForAllExplicitAddedEntities(); hbmMapping.ShowInConsole(); }
使用后置约定(Post-Conventions):
[Test] public void MapClassWithHardConventions() { var mapper = new ModelMapper(); //option:Hard-Conventions mapper.AfterMapClass += (mi, t, map) => map.Id(x => x.Column((t.Name + "id").ToUpper())); mapper.AfterMapProperty += (mi, propertyPath, map) => map.Column(propertyPath.ToColumnName().ToUpper()); mapper.Class(cm => { cm.Id(myclass => myclass.Id, map => { map.Column("MyClassId"); map.Generator(Generators.HighLow); }); cm.Property(myclass => myclass.Something, map => map.Column("Whatever")); }); var hbmMapping = mapper.CompileMappingForAllExplicitAddedEntities(); hbmMapping.ShowInConsole(); }
这个例子最终主键的映射的列名称为MYCLASSID,Something映射的列名称为SOMETHING。但是其思想有些不同。

结语

NHibernate3.2新增的Mapping-By-Code(代码映射),这篇文章结合上篇的原理从整体大运用Mapping-By-Code(代码映射)功能,有个整体方向。

参考资料

Fabio Maulo:NHibernate 3.2 mapping by code
Fabio Maulo:NHibernate 3.2: (part 2) mapping by code
Tags: 

延伸阅读

最新评论

发表评论