用于双向映射的简单约定自动映射(来自/来自ViewModels的实体)

时间:2009-11-23 08:05:29

标签: c# asp.net-mvc mapping automapper automapping

更新:这些东西已演变成一个不错的项目,请参阅http://valueinjecter.codeplex.com

<小时/> 检查一下,我刚写了一个简单的自动播放器,它从属性中获取具有相同名称和类型的一个对象的值并将其放入另一个对象中,并且可以为您可能需要的每种类型添加异常(ifs,switch)< BR />

那么请告诉我你对此有何看法?

我做到了所以我可以这样做:

Product –> ProductDTO

ProductDTO –> Product

它是如何开始的:

我在Dropsow的Inputs / Dto / ViewModels中使用“object”类型,因为我向html发送了一个IEnumerable&lt; SelectListItem&gt;然后我收到一个选定键的字符串数组

 public void Map(object a, object b)
    {
        var pp = a.GetType().GetProperties();
        foreach (var pa in pp)
        {
            var value = pa.GetValue(a, null);

            // property with the same name in b
            var pb = b.GetType().GetProperty(pa.Name);
            if (pb == null)
            {
                //no such property in b
                continue;
            }

            if (pa.PropertyType == pb.PropertyType)
            {
                pb.SetValue(b, value, null);
            }

        }
    }

更新 实际用法:
构建方法(输入= Dto):

        public static TI BuildInput<TI, T>(this T entity) where TI: class, new()
        {
            var input = new TI();
            input = Map(entity, input) as TI;
            return input;
        }

        public static T BuildEntity<T, TI, TR>(this TI input)
            where T : class, new()
            where TR : IBaseAdvanceService<T>
        {               
            var id = (long)input.GetType().GetProperty("Id").GetValue(input, null);
            var entity = LocatorConfigurator.Resolve<TR>().Get(id) ?? new T();
            entity = Map(input, entity) as T;
            return entity;
        }

        public static TI RebuildInput<T, TI, TR>(this TI input)
            where T: class, new()
            where TR : IBaseAdvanceService<T>
            where TI : class, new()
        {

                return input.BuildEntity<T, TI, TR>().BuildInput<TI, T>();
            }

在控制器中:

    public ActionResult Create()
    { 
        return View(new Organisation().BuildInput<OrganisationInput, Organisation>());
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(OrganisationInput o)
    {
        if (!ModelState.IsValid)
        {
            return View(o.RebuildInput<Organisation,OrganisationInput, IOrganisationService>());                
        }
        organisationService.SaveOrUpdate(o.BuildEntity<Organisation, OrganisationInput, IOrganisationService>());
        return RedirectToAction("Index");
    }

真正的Map方法

public static object Map(object a, object b)
        {
            var lookups = GetLookups();

            var propertyInfos = a.GetType().GetProperties();
            foreach (var pa in propertyInfos)
            {
                var value = pa.GetValue(a, null);

                // property with the same name in b
                var pb = b.GetType().GetProperty(pa.Name);
                if (pb == null)
                {
                    continue;
                }

                if (pa.PropertyType == pb.PropertyType)
                {
                    pb.SetValue(b, value, null);
                }
                else if (lookups.Contains(pa.Name) && pa.PropertyType == typeof(LookupItem))
                {
                    pb.SetValue(b, (pa.GetValue(a, null) as LookupItem).GetSelectList(pa.Name), null);
                }
                else if (lookups.Contains(pa.Name) && pa.PropertyType == typeof(object))
                {
                    pb.SetValue(b, pa.GetValue(a, null).ReadSelectItemValue(), null);
                }
                else if (pa.PropertyType == typeof(long) && pb.PropertyType == typeof(Organisation))
                {
                    pb.SetValue(b, pa.GetValue<long>(a).ReadOrganisationId(), null);
                }
                else if (pa.PropertyType == typeof(Organisation) && pb.PropertyType == typeof(long))
                {
                    pb.SetValue(b, pa.GetValue<Organisation>(a).Id, null);
                }
            }

            return b;
        }

4 个答案:

答案 0 :(得分:6)

只需使用AutoMapper即可。这很好,但它会成长为一个迷你项目。

AM(真正的)所做的一些事情是:

  • 报告您是否拥有无法映射到
  • 的属性
  • 展平对象
  • 为您提供钩子以自定义某些方面,而不是在大的开关语句中
  • 使用Expression.Compile表示性能而非直接反射

但它肯定是一个有趣的空间,而自动映射的想法肯定是有用的。

有点像1533行中的DI与NInject或其朋友 - 很酷,但为什么?。

我认为你已经阅读了article and comments regarding 2 way mapping on Jimmy's blog

答案 1 :(得分:6)

您可能想要添加的一件事是缓存反射位。如果您将对象映射两次,则可能不希望再次查找所有反射内容。此外,像GetValue和SetValue这样的东西很慢,我切换到后期委托+ Reflection.Emit来加快速度。

答案 2 :(得分:3)

只是一个想法:

有人可能想知道,如果抽象很容易映射到被抽象的抽象,那么抽象的意义是什么。

答案 3 :(得分:3)

  

你可以添加例外(ifs,switch)   对于您可能需要的每种类型

你不会这样做。认真。作用于对象类型的case语句是糟糕的OOP样式。我的意思是,非常糟糕。就像在你的肚子里喝伏特加酒一样开车。它可能会工作一段时间,但最终你会遇到麻烦。

OK Jimmy告诉你不要使用AutoMapper ......但我打赌他的意思是其他的。现在,你有没有发明过不同的东西 - 让吉米开心的事情? ;-)不,你刚刚制作了自己的半卷AutoMapper。吉米告诉你不要用它! ; - )

所以这是我的建议:忽略吉米所说的,只是想想自己......并使用AutoMapper; - )