如何让AutoMapper使用接口映射和具体映射

时间:2015-11-24 11:27:20

标签: c# inheritance automapper

我试图让AutoMapper从界面级别更新我的对象上的所有属性(DRY方法),但只有接口属性正在更新:

我已经尝试过调查并弄乱了AutoMapper文档中的包含路径,但它并没有按照我的预期工作,也不确定它是否相关:{{3 }}

以下是我的模特:

public interface IEntity {
    int Id { get; set; }
}

public interface IDatedEntity : IEntity {
    DateTime DateCreated { get; set; }
    DateTime DateModified { get; set; }
}

public interface IBMSEntity : IDatedEntity {
    string Notes { get; set; }
    bool Active { get; set; }

}

public class ProjectStatus : IBMSEntity {
    public string Name { get; set; }

    public StatusType Type { get; set; }

    public bool IsDefault { get; set; }

    #region Interface Properties
    public int Id { get; set; }
    public DateTime DateCreated { get; set; }
    public DateTime DateModified { get; set; }
    public string Notes { get; set; }
    public bool Active { get; set; }
    #endregion
}

以下是接受IDatedEntity并将其映射以便使用EntityFramework进行更新的代码部分:

public class BaseDatedEntityUpdate<T> : BaseEntityUpdate<T>, IUpdate<T> where T : class, IDatedEntity {

    public BaseDatedEntityUpdate(BMSContext context, IValidationDictionary validation) : base(context, validation) { }

    public override T Update(T entity) {
        //setting - I'd like to put this on the base mappings also
        var now = DateTime.Now;
        entity.DateModified = now;

        //mapping
        var original = dbSet.Find(entity.Id);
        Mapper.Map(entity, original);

        return original;
    }
}

我的地图配置有2个选项:

选项1: 我把我的ignore属性放在基类型上:

        //testing base/interface maps
        Mapper.CreateMap<IDatedEntity, IDatedEntity>()
            .ForMember(x => x.DateCreated, y=> {
                y.UseDestinationValue();
                y.Ignore();
            });

        Mapper.CreateMap<ProjectStatus, ProjectStatus>();

这不会忽略DateCreated所以我必须将Mapper.Map(entity, original);更改为Mapper.Map<IDatedEntity, IDatedEntity>(entity, original);但是我遇到的问题是我的项目状态属性(例如Name,Type和IsDefault)没有被映射到。

选项2: 我把映射放在我的具体类型上:

        //testing base/interface maps
        Mapper.CreateMap<IDatedEntity, IDatedEntity>();

        Mapper.CreateMap<ProjectStatus, ProjectStatus>()
            .ForMember(x => x.DateCreated, y=> {
                y.UseDestinationValue();
                y.Ignore();
            });

这在技术上按我想要的方式工作,但它不是很干。

问题:

有没有办法将映射应用于基类型并保持我的代码DRY? 即我想使用选项1,其中所有ProjectStatus(以及IDatedEntity的任何其他衍生产品)属性都被映射 - 无需创建详细的具体类型映射?

1 个答案:

答案 0 :(得分:2)

也许它不像你想的那么干,也许它有点矫枉过正;但是你可以用一点点反射和一两圈来映射每种类型。

此外,您可能只能指定一个装配 - 我只是采取了暴力方法,因为您需要一些装配。

public interface ITest
{
    DateTime CreatedAt { get; set; }
}

public class Test : ITest
{
    public string Guid { get; set; }
    public DateTime CreatedAt { get; set; }

    public Test()
    {
        CreatedAt = DateTime.Now;
    }
}

class Program
{
    static void Main(string[] args)
    {
        var mapMethod = typeof (Program).GetMethod("Map", BindingFlags.Static | BindingFlags.Public);
        foreach (var genericMapMethod in from assembly in AppDomain.CurrentDomain.GetAssemblies()
                                         from type in assembly.DefinedTypes
                                         where typeof (ITest).IsAssignableFrom(type)
                                         select mapMethod.MakeGenericMethod(type))
        {
            genericMapMethod.Invoke(null, new object[0]);
        }

        var test = new Test {Guid = Guid.NewGuid().ToString()};
        Thread.Sleep(1);
        var test2 = new Test();

        Mapper.Map(test, test2);

        Console.WriteLine(test2.Guid);
        Console.WriteLine(test.Guid == test2.Guid);
        Console.WriteLine(test.CreatedAt == test2.CreatedAt);

        Console.WriteLine("Done");
        Console.ReadLine();
    }

    public static void Map<T>() where T : ITest
    {
        Mapper.CreateMap<T, T>()
        .ForMember(x => x.CreatedAt, y => {
            y.UseDestinationValue();
            y.Ignore();
        });
    }
}

如果这是朝着正确方向迈出的一步,请告诉我 希望它有所帮助。