编辑:这最初用于1:1映射,但我发现我需要更复杂的递归映射,因此在此处发布了一个新问题:How to recursively map entity to view model with Automapper function call?
我正在尝试使用ServiceStack ConvertTo<>一般将实体类函数映射到视图模型。方法。这映射所有相似的类型和属性名称并且工作正常,但我想找到一种方法将函数的结果映射到属性。这是一些代码
实体示例:
public class Item {
public long Id {get; set;}
public List<Product> GetProducts() {
return Repository.GetAll<Product>();
}
}
ViewModel示例:
public class ItemViewModel {
public long Id {get;set;}
public List<Product> Products {get; set;}
}
理想的结果是有一个map函数,它查看实体类以查找与返回类型匹配的方法,函数名称为“Get”+ Property name,然后执行它并将结果映射到视图模型。
答案 0 :(得分:2)
虽然您可能会发现像Automapper或Value Injecter这样的内容已经包含此功能,但是没有什么可以阻止您编写快速的小实用程序方法:
public TTarget MapToViewModel<TSource, TTarget>(TSource source)
where TTarget : new()
{
var sourceType = source.GetType();
var targetProperties = typeof(TTarget).GetProperties(BindingFlags.Public | BindingFlags.Instance);
var sourceProperties = sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
var sourceMethods = sourceType.GetMethods(BindingFlags.Public | BindingFlags.Instance);
var target = Activator.CreateInstance<TTarget>();
foreach (var prop in targetProperties)
{
var sourceProp = sourceProperties.FirstOrDefault(x => x.Name == prop.Name);
if (sourceProp != null)
{
prop.SetValue(target, sourceProp.GetValue(source, null), null);
}
else
{
var sourceMethod = sourceMethods.FirstOrDefault(x => x.Name == "Get" + prop.Name);
if (sourceMethod != null)
{
prop.SetValue(target, sourceMethod.Invoke(source, null), null);
}
}
}
return target;
}
上述.FirstOrDefault
次调用中的条件只使用Name
,但您可以将它们扩展为您喜欢的任何内容。
要使用此功能,请按以下方式调用:
var itemViewModel = MapToViewModel<Item, ItemViewModel>(item);
如果您的常规模型中的方法有任何参数,请务必小心。如果您发现模型过于复杂(或者不遵循一个或两个命名约定),那么使用AutoMapper之类的东西可能会更好。但是对于简单的映射,这样的事情应该可以胜任。
答案 1 :(得分:1)
使用ServiceStack进行此映射很难做出一般解决方案,因为您基本上必须自己编写代码以使Products
与GetProducts
匹配。
您可以使用其他映射库,例如AutoMapper,它会自动使用GetX()
填充X
。
// one time config
Mapper.CreateMap<Item, ItemViewModel>();
Mapper.AssertConfigurationIsValid();
// whenever you map
Item item = // whatever
ItemViewModel viewModel = Mapper.Map<ItemViewModel>(item);
// viewModel.Products is populated from item.GetProducts()
手动更改某些事物的映射方式也更容易,例如:您可以使用此CreateMap
手动设置此项:
Mapper.CreateMap<Item, ItemViewModel>()
.ForMember(dest => dest.Products,
opt => opt.ResolveUsing(src => src.GetProducts()));
看起来AutoMapper是一个更强大的映射器。即使您将ServiceStack用于其他部分,也可能需要使用AutoMapper进行映射。