如何让AutoMapper使用接口映射和具体映射
How to get AutoMapper to use interface mappings and concrete mappings
我试图让 AutoMapper 从接口级别(DRY 方法)更新我的对象的所有属性,但只有接口属性正在更新:
我已经尝试研究和弄乱 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();
});
这在技术上按照我想要的方式工作,但它不是很干。
问题:
有没有办法将映射应用到基类型并保持我的代码干燥?
IE。我想使用选项 1,从而映射所有 ProjectStatus(以及 IDatedEntity 的任何其他派生)属性 - 无需创建详细的具体类型映射?
也许它不像你喜欢的那么枯燥,也许有点矫枉过正;p 但你可以用一点反射和一两个循环来映射每种类型。
您也可以只指定一个程序集 - 我只是采用了一种蛮力方法,以防您需要几个程序集。
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();
});
}
}
让我知道这是否是朝着正确方向迈出的一步。
希望对你有帮助。
我试图让 AutoMapper 从接口级别(DRY 方法)更新我的对象的所有属性,但只有接口属性正在更新:
我已经尝试研究和弄乱 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();
});
这在技术上按照我想要的方式工作,但它不是很干。
问题:
有没有办法将映射应用到基类型并保持我的代码干燥? IE。我想使用选项 1,从而映射所有 ProjectStatus(以及 IDatedEntity 的任何其他派生)属性 - 无需创建详细的具体类型映射?
也许它不像你喜欢的那么枯燥,也许有点矫枉过正;p 但你可以用一点反射和一两个循环来映射每种类型。
您也可以只指定一个程序集 - 我只是采用了一种蛮力方法,以防您需要几个程序集。
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();
});
}
}
让我知道这是否是朝着正确方向迈出的一步。
希望对你有帮助。