嗨我有一些自动映射器的主要问题,它很慢。我不知道如何加快速度。
我正在使用nhibernate,流利的nhibernate和asp.net mvc 3.0
[Serializable()]
public class Test
{
public virtual int Id { get; private set; }
public virtual string Name { get; set; }
public virtual string Description { get; set; }
public virtual DateTimeDate { get; set; }
public virtual IList<Reminder> Reminders { get; set; }
public virtual IList<Reminder2> Reminders2 { get; set; }
public virtual Test2 Test2 { get; set; }
public Test()
{
Reminders = new List<Reminders>();
Reminders2 = new List<Reminders2>();
}
}
因为你可以看到我有一些属性,在我的数据库中的其他一些类我之间有引用。
然后我这样做
var a = // get all items (returns a collection of Test2)
var List<MyViewModel> collection = new List<MyViewModel>();
foreach (Test2 t in a)
{
MyViewModel vm = Mapper.Map<Test2, MyViewModel>(t);
vm.SetDateFormat(t.DateTimeDate, DateFilters.All.ToString());
collection.Add(vm);
}
//查看模型
public class MyViewModel
{
public int Id { get; private set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime DateTimeDate { get; set; }
public string FormatedDueDate { get; set; }
public string Test2Prefix { get; set; }
public string Test2BackgroundColor { get; set; }
public string SelectedDateFilter { get; set; }
public bool DescState { get; set; }
public bool AlertState { get; set; }
/// <summary>
/// Constructor
/// </summary>
public MyViewModel()
{
// Default values
SelectedDateFilter = "All";
DescState = false;
AlertState = false;
}
/// <summary>
/// Sets the date formatter string used
/// </summary>
/// <param name="dateFormat"></param>
public void SetDateFormat(DateTime dueDate, string dateFilter)
{
// simple if statement to format date.
}
}
// mapping
Mapper.CreateMap<Test2,MyViewModel>().ForMember(dest => dest.DescState, opt =>
opt.ResolveUsing<DescStateResolver>())
.ForMember(dest => dest.AlertState, opt =>
opt.ResolveUsing<AlertStateResolver>());
//解析器
public class AlertStateResolver : ValueResolver<Task, bool>
{
protected override bool ResolveCore(Task source)
{
if (source.Reminders.Count > 0 || source.Reminders2.Count > 0)
{
return true;
}
else
{
return false;
}
}
}
public class DescStateResolver : ValueResolver<Task,bool>
{
protected override bool ResolveCore(Task source)
{
if (String.IsNullOrEmpty(source.Description))
{
return false;
}
else
{
return true;
}
}
}
忽略奇怪的名字和任何拼写错误我的真实对象工作正常并且有意义。
所以我用了秒表并做了这个
Stopwatch a = new Stopwatch()
foreach (Test2 t in a)
{
a.Start()
MyViewModel vm = Mapper.Map<Test2, MyViewModel>(t);
a.Stop()
vm.SetDateFormat(t.DateTimeDate, DateFilters.All.ToString());
collection.Add(vm);
}
var b = a.Elapsed; // comes back with 32 seconds.
我需要非常好地优化它。
答案 0 :(得分:27)
要寻找的另一件事是映射抛出异常的代码。 AutoMapper将以静默方式捕获这些内容,但以这种方式捕获异常会影响性能。
因此,如果SomethingThatMightBeNull通常为null,那么由于NullreferenceExceptions,此映射将表现不佳:
.ForMember(dest => dest.Blah, c.MapFrom(src=>src.SomethingThatMightBeNull.SomeProperty))
我发现这样的更改将超过映射所用时间的一半:
.ForMember(dest => dest.Blah, c.MapFrom(src=> (src.SomethingThatMightBeNull == null
? null : src.SomethingThatMightBeNull.SomeProperty)))
更新:C#6语法
.ForMember(dest => dest.Blah, c.MapFrom(src => (src.SomethingThatMightBeNull?.SomeProperty)))
答案 1 :(得分:26)
而不是:
var a = // get all items (returns a collection of Test2)
List<MyViewModel> collection = new List<MyViewModel>();
foreach (Test2 t in a)
{
MyViewModel vm = Mapper.Map<Test2, MyViewModel>(t);
vm.SetDateFormat(t.DateTimeDate, DateFilters.All.ToString());
collection.Add(vm);
}
尝试:
var a = // get all items (returns a collection of Test2)
List<MyViewModel> collection = Mapper.Map<IEnumerable<Test2>, IEnumerable<MyViewModel>>(a);
这相当于您可以在映射定义中执行的SetDateFormat
调用之外的第一个调用。它也可能更快。
如果您在Test2 => MyViewModel
之间定义了映射,则AutoMapper会自动为IEnumerable<Test2> => IEnumerable<MyViewModel>
提供一个映射,以便您无需循环。
你也在你的问题中提到过NHibernate。确保源对象及其集合是从数据库中强烈加载之前将其传递给映射层,否则你不能责怪AutoMapper因为它试图映射其中一个集合时很慢源对象它命中数据库,因为NHibernate没有获取此集合。
答案 2 :(得分:12)
添加此
后能够改善启动时间 .ForAllMembers(options => options.Condition(prop => prop.SourceValue != null));
在每个
结束时.CreateMap<..,..>()
答案 3 :(得分:3)
如果你的子集合很大,你可能会因使用“Any()”而不是“Count&gt; 1”而受益。 Any函数只需迭代一次,而Count可能需要迭代entmes集合(取决于实现)。
答案 4 :(得分:1)
不确定这是否会导致您的案例出现任何问题,但请注意序列化自动实现的属性。
每次编译代码时,编译器都会随机选取每个(匿名)支持字段的名称。因此,如果使用一次编译的progran序列化数据并使用不同的程序对其进行反序列化,则可能会看到一些令人惊讶的异常。
答案 5 :(得分:0)
我修复了与你相同的问题。仅映射一个对象也需要花费32秒。 所以,我使用opts.Ignore()来处理一些自定义对象,如下所示:
CreateMap<SiteConfiguration, Site>()
.ForMember(x => x.SubSystems, opts => opts.Ignore())
.ForMember(x => x.PointInformations, opts => opts.Ignore())
.ForMember(x => x.Schedules, opts => opts.Ignore())
.ForMember(x => x.EquipmentDefinitions, opts => opts.Ignore());
之后,它只需几毫秒。
答案 6 :(得分:0)
一个好的技巧是优化AutoMapper的配置,对ViewModels的属性使用Ignore,并进行方法调用以验证映射“ Mapper.AssertConfigurationIsValid()” 。
$ sudo service mysql restart