Automapper:如何利用自定义INamingConvention?

时间:2012-02-23 17:45:46

标签: automapper automapper-2

我正在使用一个数据库,设计师似乎真的喜欢大写字母和下划线键。由于我有一个简单的ORM,我的数据模型也使用这些名称。我需要构建DTO,我更愿意给它们标准名称,因为我们通过服务公开它们。 以下代码现已更正!测试通过,因此如果您需要使用多个命名约定,请将此作为参考

    using System;
    using System.Collections.Generic;
    using System.Text.RegularExpressions;
    using AutoMapper;
    using NUnit.Framework;

    namespace AutomapperTest
    {
        public class DATAMODEL
        {
            public Guid ID { get; set; }
            public string FIRST_NAME { get; set; }
            public List<CHILD_DATAMODEL> CHILDREN { get; set; }
        }

        public class CHILD_DATAMODEL
        {
            public Guid ID { get; set; }
            public int ORDER_ID { get; set; }
        }

        public class DataModelDto
        {
            public Guid Id { get; set; }
            public string FirstName { get; set; }
            public List<ChildDataModelDto> Children { get; set; }
        }

        public class ChildDataModelDto
        {
            public Guid Id { get; set; }
            public int OrderId { get; set; }
        }

        public class UpperUnderscoreNamingConvention : INamingConvention
        {
            private readonly Regex _splittingExpression = new Regex(@"[\p{Lu}0-9]+(?=_?)");

            public Regex SplittingExpression { get { return _splittingExpression; } }

            public string SeparatorCharacter { get { return "_"; } }
        }

        public class Profile1 : Profile
        {
            protected override void Configure()
            {
                SourceMemberNamingConvention = new UpperUnderscoreNamingConvention();
                DestinationMemberNamingConvention = new PascalCaseNamingConvention();
                CreateMap<DATAMODEL, DataModelDto>();
                CreateMap<CHILD_DATAMODEL, ChildDataModelDto>();
            }
        }
        [TestFixture]
        public class Tests
        {
            [Test]
            public void CanMap()
            {
                //tell automapper to use my convention
                Mapper.Initialize(x => x.AddProfile<Profile1>());
                //make a dummy source object
                var src = new DATAMODEL();
                src.ID = Guid.NewGuid();
                src.FIRST_NAME = "foobar";
                src.CHILDREN = new List<CHILD_DATAMODEL>
                               {
                                   new CHILD_DATAMODEL()
                                       {
                                           ID = Guid.NewGuid(),
                                           ORDER_ID = 999
                                       }
                               };
                //map to destination
                var dest = Mapper.Map<DATAMODEL, DataModelDto>(src);
                Assert.AreEqual(src.ID, dest.Id);
                Assert.AreEqual(src.FIRST_NAME, dest.FirstName);
                Assert.AreEqual(src.CHILDREN.Count, dest.Children.Count);
                Assert.AreEqual(src.CHILDREN[0].ID, dest.Children[0].Id);
                Assert.AreEqual(src.CHILDREN[0].ORDER_ID, dest.Children[0].OrderId);
            }
        }
    }

2 个答案:

答案 0 :(得分:1)

怎么样?
public class DATAMODELProfile : Profile
{
    protected override void Configure()
    {
        Mapper.CreateMap<DATAMODEL, DATAMODEL>();
        Mapper.CreateMap<DATAMODEL, SOMETHINGELSE>();
        Mapper.CreateMap<DATAMODEL, DataModelDto>()
            .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.ID))
            .ForMember(dest => dest.FirstName, opt => opt.MapFrom(src => src.FIRST_NAME))
            .ForMember(dest => dest.ChildDataModels, opt => opt.MapFrom(src => src.CHILD_DATAMODELS));
    }
}

答案 1 :(得分:1)

在配置文件中创建映射,并根据需要定义INamingConvention参数。

我不喜欢全局/静态,所以我更喜欢使用Initialize并将所有映射定义在一起。这也有一个额外的好处,允许调用AssertConfiguration ...这意味着如果我已经borked我的映射我将在启动时获得异常,而不是每当我的代码使用有问题的映射。

Mapper.Initialize(configuration =>
{
    configuration.CreateProfile("Profile1", CreateProfile1);
    configuration.CreateProfile("Profile2", CreateProfile2);
});
Mapper.AssertConfigurationIsValid();

与该初始化方法在同一个类中:

public void CreateProfile1(IProfileExpression profile)
{
    // this.CreateMap (not Mapper.CreateMap) statements that do the "normal" thing here
    // equivalent to Mapper.CreateMap( ... ).WithProfile("Profile1");
}

public void CreateProfile2(IProfileExpression profile)
{
    profile.SourceMemberNamingConvention = new PascalCaseNamingConvention();
    profile.DestinationMemberNamingConvention = new LowerUnderscoreNamingConvention();

    // this.CreateMap (not Mapper.CreateMap) statements that need your special conventions here
    // equivalent to Mapper.CreateMap( ... ).WithProfile("Profile2");
}

如果你这样做,并且没有在两个配置文件中定义相同的映射,我认为你不需要从原始问题“填空”,它应该已经设置为对的。