2015-11-24 111 views
3

我试图让AutoMapper更新从接口级(干法)我对象所有的属性,但只有接口属性被更新:如何获得AutoMapper使用接口映射,具体映射

我已经试过寻找到,并与来自AutoMapper文档包含路径乱搞,但它不工作我所期望的和不知道的方式,如果它甚至相关:https://github.com/AutoMapper/AutoMapper/wiki/Mapping-inheritance

这里是我的模型:

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: 我把我忽略性能上基本类型:

 //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);但随后我有我的项目状态属性(如名称,类型和IsDefault)没有得到映射的问题。

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

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

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

这在技术上的作品我希望它的方式,但不是很干。

问:

是否有可以映射适用于基本类型,并保持我的代码干的方法吗? 也就是说我想要使​​用选项1,即所有ProjectStatus(以及IDatedEntity的任何其他衍生物)属性都被映射 - 无需创建详细的具体类型映射?

回答

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(); 
     }); 
    } 
} 

让我知道如果这是一个正确的方向迈出的一步。
希望它有帮助。

+0

2个问题,这实际上工作?我是否认为我只需要在应用程序启动时运行此注册地图? – Smithy

+1

它可以工作,您可以将其粘贴到控制台应用程序中并运行它进行测试。是的,你可以只运行一次。 请注意,因为有一些反映,启动会慢一点 – sQuir3l

+1

这是一个Web应用程序,所以启动不是一个问题,你是一个天才的人,谢谢你! – Smithy