zoukankan      html  css  js  c++  java
  • 映射层超类型

    映射层超类型

    上一篇介绍了工作单元层超类型的封装演化过程,本文将介绍对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 

    版权所有,转载请注明出处 何镇汐的技术博客
     
  • 相关阅读:
    Begin Example with Override Encoded SOAP XML Serialization
    State Machine Terminology
    How to: Specify an Alternate Element Name for an XML Stream
    How to: Publish Metadata for a WCF Service.(What is the Metadata Exchange Endpoint purpose.)
    Beginning Guide With Controlling XML Serialization Using Attributes(XmlSerializaiton of Array)
    Workflow 4.0 Hosting Extensions
    What can we do in the CacheMetaData Method of Activity
    How and Why to use the System.servicemodel.MessageParameterAttribute in WCF
    How to: Begin Sample with Serialization and Deserialization an Object
    A Test WCF Service without anything of config.
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/4151953.html
Copyright © 2011-2022 走看看