随着我对ASP.Net MVC 3的学习和使用,我开始尝试使用AutoMapper来映射领域实体和视图模型。
在单独为每个实现的视图模型创建映射的过程中,我感到有些厌烦。因此,我编写了一些代码来扫描我的程序集,并使用一些反射来创建所需的每个映射。然而,由于我并不是很熟悉使用AutoMappers的最佳实践,所以我想展示给大家我做的事情,并问问我的方法是否会带来问题。
本质上,我有一个名为AutoMappingConfigurator的类(用于Global.asax.cs),如下所示:
基本上,它会扫描程序集中所有标记了AutoMapAttribute的类型,并为找到的每个类型创建双向映射。
AutoMapAttribute是我创建的一个简单属性(基于我在网上找到的示例),我将其附加到我的ViewModel上,以指示它映射到哪个Domain Entity。
例如。
关于 IgnoreProperties 扩展方法,我发现每当我有一个视图模型包含一个我想要忽略的属性(例如当我的视图模型有一个下拉列表,而该下拉列表不是基础域实体的一部分时),我似乎必须手动创建忽略项,通过使用 ForMember AutoMapper 方法。因此,我创建了另一个属性来指示哪些属性应该被忽略,这样我的 AutoMappingConfigurator 中的反射代码就可以自动为我执行此操作。
IgnoreProperties 扩展方法是作为扩展方法实现的,如下所示:
所有这些都让我可以编写以下的ViewModel并自动映射它:
在单独为每个实现的视图模型创建映射的过程中,我感到有些厌烦。因此,我编写了一些代码来扫描我的程序集,并使用一些反射来创建所需的每个映射。然而,由于我并不是很熟悉使用AutoMappers的最佳实践,所以我想展示给大家我做的事情,并问问我的方法是否会带来问题。
本质上,我有一个名为AutoMappingConfigurator的类(用于Global.asax.cs),如下所示:
public static class AutoMappingConfigurator
{
public static void Configure(Assembly assembly)
{
var autoMappingTypePairingList = new List<AutoMappingTypePairing>();
foreach (Type t in assembly.GetTypes())
{
var autoMapAttribute = t
.GetCustomAttributes(typeof(AutoMapAttribute), true)
.OfType<AutoMapAttribute>()
.FirstOrDefault();
if (autoMapAttribute != null)
{
autoMappingTypePairingList
.Add(new AutoMappingTypePairing(autoMapAttribute.SourceType, t));
}
}
autoMappingTypePairingList
.ForEach(mappingPair => mappingPair.CreateBidirectionalMap());
}
}
基本上,它会扫描程序集中所有标记了AutoMapAttribute的类型,并为找到的每个类型创建双向映射。
AutoMapAttribute是我创建的一个简单属性(基于我在网上找到的示例),我将其附加到我的ViewModel上,以指示它映射到哪个Domain Entity。
例如。
[AutoMap(typeof(Project))]
public class ProjectDetailsViewModel
{
public int ProjectId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
就双向映射而言,在我使用MVC3的工作中,我发现在HttpGet时经常需要从实体映射到ViewModel,而在HttpPost时需要从ViewModel映射到实体。
双向映射是通过以下扩展方法实现的:
public static void CreateBidirectionalMap(this AutoMappingTypePairing mappingPair)
{
Mapper.CreateMap(mappingPair.SourceType, mappingPair.DestinationType)
.IgnoreProperties(mappingPair.DestinationType);
Mapper.CreateMap(mappingPair.DestinationType, mappingPair.SourceType)
.IgnoreProperties(mappingPair.SourceType);
}
关于 IgnoreProperties 扩展方法,我发现每当我有一个视图模型包含一个我想要忽略的属性(例如当我的视图模型有一个下拉列表,而该下拉列表不是基础域实体的一部分时),我似乎必须手动创建忽略项,通过使用 ForMember AutoMapper 方法。因此,我创建了另一个属性来指示哪些属性应该被忽略,这样我的 AutoMappingConfigurator 中的反射代码就可以自动为我执行此操作。
IgnoreProperties 扩展方法是作为扩展方法实现的,如下所示:
public static IMappingExpression IgnoreProperties(this IMappingExpression expression
, Type mappingType)
{
var propertiesWithAutoMapIgnoreAttribute =
mappingType.GetProperties()
.Where(p => p.GetCustomAttributes(typeof(AutoMapIgnoreAttribute), true)
.OfType<AutoMapIgnoreAttribute>()
.Count() > 0);
foreach (var property in propertiesWithAutoMapIgnoreAttribute)
{
expression.ForMember(property.Name, opt => opt.Ignore());
}
return expression;
}
所有这些都让我可以编写以下的ViewModel并自动映射它:
[AutoMap(typeof(EntityClass))]
private class ViewModelClass
{
public int EntityClassId { get; set; }
[AutoMapIgnore]
public IEnumerable<SelectListItem> DropDownItems { get; set; }
}
private class EntityClass
{
public int EntityClassId { get; set; }
}
虽然目前这种方法对我来说有效,但由于我在AutoMapper方面的经验较少,我担心它可能会给我带来麻烦。
所以我的问题是:
- 这种设置AutoMapper来配置领域实体和ViewModel之间映射的方式是否好?
- 有没有关于AutoMapper的内容我可能会忽略而使这种方法变得不好?
- 通过反射和属性连接Ignore属性是否是一个好主意?
- 创建实体和ViewModel之间双向映射是否是个好主意?