需要加速自动化...需要32秒才能完成113个对象

时间:2011-03-06 03:46:57

标签: c# performance nhibernate asp.net-mvc-3 automapper

嗨我有一些自动映射器的主要问题,它很慢。我不知道如何加快速度。

我正在使用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.

我需要非常好地优化它。

7 个答案:

答案 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