首页 > 代码库 > 应用程序框架实战二十:映射层超类型

应用程序框架实战二十:映射层超类型

  上一篇介绍了工作单元层超类型的封装演化过程,本文将介绍对Entity Framework映射层超类型的封装。

  使用Entity Framework一般需要映射三种类型的对象,即实体、聚合、值对象。

  聚合与实体映射的主要区别是:聚合映射单属性标识Id,并需要映射乐观离线锁Version,而实体的标识往往需要映射成复合属性,这样方便物理删除聚合中的实体。Entity Framework通过EntityTypeConfiguration进行实体映射。

  值对象以嵌入值模式映射,这需要使用ComplexTypeConfiguration。

  封装映射配置并不是必须的,但封装以后可以获得如下好处。

  1. 辅助记忆

  如果你跟我一样记忆力很差,记不住上面两个类名,那么通过封装一个自定义的类型可以帮助你进行记忆。一旦封装完成,你就可以把系统或第三方的Api扔到一边。

  2. 划分逻辑结构

  把所有映射代码放到一个方法,不方便阅读,我把它们划分成不同的方法,可以获得更清晰的结构。

  3. 减少代码冗余

  对于聚合而言,可以把Id标识和Version乐观离线锁封装到层超类型,从而减少代码冗余。  

映射层超类型实现

  实体映射基类EntityMapBase

  EntityMapBase从EntityTypeConfiguration继承,泛型参数TEntity使用IEntity接口约束,构造方法将映射配置从逻辑上分离到4个方法中,即映射表、映射标识、映射属性、映射导航属性。

  在构造方法中调用虚方法有时候可能导致意想不到的错误,这种情况发生在子类构造方法的代码依赖某些虚方法,由于调用顺序混乱可能导致失败,不过这种情况还是比较少见,如果你碰到上述问题,请果断扔掉该映射基类,直接从EntityTypeConfiguration派生。

  EntityMapBase用于映射实体,代码如下。

using System.Data.Entity.ModelConfiguration;using Util.Domains;namespace Util.Datas.Ef {    /// <summary>    /// 实体映射    /// </summary>    /// <typeparam name="TEntity">实体类型</typeparam>    public abstract class EntityMapBase<TEntity> : EntityTypeConfiguration<TEntity> where TEntity : class, IEntity {        /// <summary>        /// 初始化映射        /// </summary>        protected EntityMapBase() {            MapTable();            MapId();            MapProperties();            MapAssociations();        }        /// <summary>        /// 映射表        /// </summary>        protected abstract void MapTable();        /// <summary>        /// 映射标识        /// </summary>        protected abstract void MapId();        /// <summary>        /// 映射属性        /// </summary>        protected virtual void MapProperties() {        }        /// <summary>        /// 映射导航属性        /// </summary>        protected virtual void MapAssociations() {        }    }}

聚合映射基类AggregateMapBase

  AggregateMapBase继承于EntityMapBase,并重写了MapId和MapProperties,对标识Id和乐观锁进行映射。

  另外,提供了两个泛型版本的AggregateMapBase, 提供AggregateMapBase<TEntity>的目的是使聚合映射更易用,因为我的大多数聚合都使用Guid类型,这样可以省一个参数。

  AggregateMapBase用于映射聚合,代码如下。

using System;using System.ComponentModel.DataAnnotations.Schema;using Util.Domains;namespace Util.Datas.Ef {    /// <summary>    /// 聚合根映射    /// </summary>    /// <typeparam name="TEntity">聚合根类型</typeparam>    /// <typeparam name="TKey">实体标识类型</typeparam>    public abstract class AggregateMapBase<TEntity, TKey> : EntityMapBase<TEntity> where TEntity : AggregateRoot<TKey> {        /// <summary>        /// 映射标识        /// </summary>        protected override void MapId() {            HasKey( t => t.Id );        }        /// <summary>        /// 映射属性        /// </summary>        protected override void MapProperties() {            Property( t => t.Version ).HasColumnName( "Version" ).IsRowVersion().HasDatabaseGeneratedOption( DatabaseGeneratedOption.Computed ).IsOptional();        }    }    /// <summary>    /// 聚合根映射    /// </summary>    /// <typeparam name="TEntity">聚合根类型</typeparam>    public abstract class AggregateMapBase<TEntity> : AggregateMapBase<TEntity, Guid> where TEntity : AggregateRoot<Guid> {    }}

  值对象映射基类ValueObjectMapBase

  ValueObjectMapBase从ComplexTypeConfiguration继承,它唯一需要的就是映射属性,创建这个类只有一个原因——帮助你记忆。

  ValueObjectMapBase用于映射值对象,代码如下。 

using System.Data.Entity.ModelConfiguration;namespace Util.Datas.Ef {    /// <summary>    /// 值对象映射    /// </summary>    /// <typeparam name="TValueObject">值对象类型</typeparam>    public abstract class ValueObjectMapBase<TValueObject> : ComplexTypeConfiguration<TValueObject> where TValueObject : class {        /// <summary>        /// 初始化值对象映射        /// </summary>        protected ValueObjectMapBase() {            MapProperties();        }        /// <summary>        /// 映射属性        /// </summary>        protected abstract void MapProperties();    }}

  之所以说映射基类不是必须的,是因为映射配置一般由代码生成器创建,所以能够从基类获得的好处不是非常明显。另外,很多人会觉得这导致过度封装。创建这几个类在很大程度上属于我个人习惯问题,介绍它们的目的是想告诉你,如果不想动脑筋记忆,就自己封装一层。 

  .Net应用程序框架交流QQ群: 386092459,欢迎有兴趣的朋友加入讨论。

  谢谢大家的持续关注,我的博客地址:http://www.cnblogs.com/xiadao521/

  下载地址:http://files.cnblogs.com/xiadao521/Util.2014.12.8.1.rar 

应用程序框架实战二十:映射层超类型