• 热门专题

AutoMapper对internal访问级别属性的映射

作者:draculav  发布日期:2014-06-05 20:01:52
Tag标签:属性  级别  
  •   最近在使用DDD重新搭建公司内部OA的架构,具体情况搭好了应该会写一下,这里说的是今天遇到的问题。

      先简单说一下相关的几个部分:

      1.聚合。聚合分成了两个模块:一个包含审批单据等估计至少今年不会怎么变的抽象模型;另外一个包含不同审批单据的实现类,继承至抽象的模块;由于主要是要说这一块,就贴一点部分代码上来,与本随笔要说的无关的部分就省略号了。。。

      [DomainAttribute(DomainType = ApplyDomainType.Root, Description = "申请单")]
        public class RequisitionBase
        {
            internal int ID { get; set; }
            internal string ProcesssCode { get; set; }
    
            /// <summary>
            /// 流程类型,定义流程类型,例如“TB”,“HT”等
            /// </summary>
            internal string ProcessType { get; set; }
    
            /// <summary>
            /// 申请人域帐号
            /// </summary>
            internal string ApplicantUserID { get; set; }
    
            /// <summary>
            /// 申请人姓名
            /// </summary>
            internal string ApplicantUserName { get; set; }
    
            /// <summary>
            /// 申请日期
            /// </summary>
            internal DateTime ApplicantDate { get; set; }
    
            //还有一些属性和方法,不过都不重要了
        }
        public class AllographRequisition : RequisitionBase
        {
            public AllographRequisition()
            {
                //代签项目申请单实现类,略。。。
            }
        }

      2.用于UI和应用层之间传数据的DTO,命名应该用信息的,不过咱纯粹的不愿意用那个单词。。。

        public class AllographRequisitionData
        {
            //方便测试
            public AllographRequisitionData(AllographRequisitionData data)
            {
                Project = data.Project;
                RequisitionContent = data.RequisitionContent;
            }
    
            public AllographRequisitionData(ProjectContentData project, AllographRequisitionContentData requisitionContent)
            {
                Project = project;
                RequisitionContent = requisitionContent;
            }
    
            public ProjectContentData Project { get; set; }
            public AllographRequisitionContentData RequisitionContent { get; set; }
    
            public int ID { get; set; }
            public string ProcesssCode { get; set; }
    
            /// <summary>
            /// 流程类型,定义流程类型,例如“TB”,“HT”等
            /// </summary>
            public string ProcessType { get; set; }
    
            /// <summary>
            /// 申请人域帐号
            /// </summary>
            public string ApplicantUserID { get; set; }
    
            /// <summary>
            /// 申请人姓名
            /// </summary>
            public string ApplicantUserName { get; set; }
    
            /// <summary>
            /// 申请日期
            /// </summary>
            public DateTime ApplicantDate { get; set; }
    
            //一些属性。。。  
        }

      3.应用服务,这随笔发生的地方,DTO与聚合映射的所在,只是个简单的意思,不要太在意

            public AllographRequisition DataToEntity(AllographRequisitionData data)
            {
                Mapper.CreateMap<AllographRequisitionData, AllographRequisition>();
    
                AllographRequisition requisition 
                    = Mapper.Map<AllographRequisitionData, AllographRequisition>(data);
                DateTime date = requisition.ApplicantDate;
                return requisition;
            }

      4.单元测试,因为应用层咱是用TDD开始的。。。

            [TestMethod]
            public void Save()
            {
                RequisitionService service = new RequisitionService();
                AllographRequisitionData t = new AllographRequisitionData(service.GetTestData());
                t.ApplicantDate = DateTime.Now;
                var data = service.Save(t);
    
                Assert.IsInstanceOfType(data, typeof(AllographRequisition));
                Assert.AreEqual(data.ApplicantDate, t.ApplicantDate);
            }

      由于咱这的程序员节操无法保证,无奈之下,领域层中的聚合都被我用了internal的访问级别,保证即使他们引用了,也看的见摸不着,然后使用了友元的方式对特定的几个模块提供访问,抽象的模型所在模块的代码不对程序员公开,以此来保证封装好的逻辑不被胡乱引用而破坏。

    [assembly: InternalsVisibleTo("ChanceVariation.Application.ApplicationService")]

      于是,拖了半天的剧情终于来到了正文部分,一般情况下用AutoMapper的时候都是映射public的属性,不过只要能访问的应该都是可以映射的,该怎么办呢,这几天google用域名访问不正常,懒得翻IP,只好先百度,不得不说百度对于中文分词是好些,可惜搜技术问题相当不给力,没发现一点有用的。于是只好去github上下AutoMapper的开源代码,由于我现在的系统只能装VS2012所以没办法连代码调试,只好一点点看,然后结合StackOverFlow上的一些讨论,终于找到了这个方法

            public IMappingExpression<TSource, TDestination> IgnoreAllPropertiesWithAnInaccessibleSetter()
            {
                var properties = typeof(TDestination).GetProperties().Where(HasAnInaccessibleSetter);
                foreach (var property in properties)
                    ForMember(property.Name, opt => opt.Ignore());
                return new MappingExpression<TSource, TDestination>(_typeMap, _serviceCtor, _configurationContainer);
            }

    此方法也可以解决private set不能映射的情况

    internal DateTime ApplicantDate { get; private set; }

    使用方法:

    Mapper.CreateMap<AllographRequisitionData, AllographRequisition>()
                    .IgnoreAllPropertiesWithAnInaccessibleSetter()
                    .ForMember(dest => dest.ApplicantDate, opt => opt.MapFrom(source => source.ApplicantDate));

    总算是映射成功了,不过终归是有些麻烦,暂时没时间管它了,这个月过去再琢磨有木有好办法。

About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规