【问题标题】:converting entities to viewmodels for use with web api将实体转换为视图模型以与 Web api 一起使用
【发布时间】:2013-08-08 23:21:30
【问题描述】:

我目前正在努力寻找一种更好的方法来用我的Entitiy 对象填充我的ViewModel 对象。我有以下Web Api 控制器方法:

[HttpGet]
public IEnumerable<ClientSearchViewModel> FindClients(string query)
{
    var clients = _clientService.SearchClient(query).ToList();
    var returnClients = new List<ClientSearchViewModel>();
    foreach (var client in clients)
    {
        returnClients.Add(new ClientSearchViewModel(client));
    }
    return returnClients;
}

我在我的 ClientSearchViewModel 构造函数中这样做:

public ClientSearchViewModel(Client client)
{
    this.Id = client.Id;
    this.FirstName = client.PersonName.FirstName;
    this.LastName = client.PersonName.LastName;
}

除了遍历返回的对象列表并创建一个新的ViewModel 列表之外,还有其他方法吗?

【问题讨论】:

    标签: c# entity-framework asp.net-mvc-4 asp.net-web-api


    【解决方案1】:

    我强烈建议为此使用映射插件,例如:

    AutoMapper

    ValueInjector

    这样的插件将允许您在内部或数据层中使用的对象与外部对象(DTO/ViewModel)之间进行映射。它们处理许多开箱即用的事情,例如自动映射具有相同类型的任何类似命名的属性,但还允许对属性或类型的特定映射进行大量控制,以便在您需要更多自定义的时候进行.

    对于两者的简要比较,没有比听到作者自己回复更好的了:AutoMapper vs ValueInjecter

    就个人而言,我发现 ValueInjector 使用起来更快,同时总体上具有更多的控制权,但我也发现它比 AutoMapper 的可读性/直观性要低得多,后者可能需要更多的代码来实现类似的目标。因此,我会选择您发现和/或您的团队会更喜欢其语法以及您掌握概念的难易程度与您真正需要的功能的一个。

    【讨论】:

    • 个人偏好其中之一?还是两者都有一些快速的利弊?
    • 添加了一个链接,其中包含来自实际作者的更多信息。
    【解决方案2】:

    所以我有同样的 miff...我不能说我已经对我的解决方案进行了基准测试,但它似乎运行得相当快...

    3 位:

    public static T Transform<T>(this object convertFrom) where T : class, new()
            {
                return (T) (new ServiceExtension().Transform(convertFrom, typeof (T)));
    
            }
    
    private class ServiceExtension
            {
                public object Transform(object convertFrom, Type convertTo)
                {
                    object _t = Activator.CreateInstance(convertTo);
                    if (convertFrom == null) return _t;
    
                    var convertType = convertFrom.GetType();
                foreach (
                    var property in _t.GetType().GetProperties().Where(f => f.CanWrite && f.GetSetMethod(true).IsPublic)
                    )
                {
                    if (property.GetCustomAttributes(typeof (TransformAttribute), true).Any())
                    {
                        var transform =
                            (property.GetCustomAttributes(typeof (TransformAttribute), true).FirstOrDefault() as
                             TransformAttribute);
                        var transformname = transform.RelatedField ?? property.Name;
    
                        if (convertType.GetProperty(transformname) == null)
                            throw new ArgumentException(
                                string.Format(
                                    "We were unable to find property:\"{0}\" on {1}.  Please check the RelativeField value on the {2} for \"{0}\"",
                                    transformname, convertFrom.GetType().Name, convertTo.Name));
    
                        var theValue = convertType.GetProperty(transformname).GetValue(convertFrom);
    
                        if (isCollection(theValue))
                        {
                            foreach (var item in (theValue as ICollection))
                            {
                                var someVal = new object();
                                var newToType = property.PropertyType.GetGenericArguments().FirstOrDefault();
    
                                if (!String.IsNullOrEmpty(transform.FullyQualifiedName))
                                    someVal =
                                        Transform(
                                            item.GetType().GetProperty(transform.FullyQualifiedName).GetValue(item),
                                            newToType);
    
                                else
                                    someVal = Transform(item, newToType);
                                if (property.GetValue(_t) == null)
                                    throw new NullReferenceException(
                                        string.Format(
                                            "The following property:{0} is null on {1}.  Likely this needs to be initialized inside of {1}'s empty constructor",
                                            property.Name, _t.GetType().Name));
                                property.PropertyType.GetMethod("Add")
                                        .Invoke(property.GetValue(_t), new[] {someVal});
                                //property.SetValue(_t, theValue.Transform(theValue.GetType()));
                            }
                        }
                        else
                            property.SetValue(_t, theValue);
                    }
                    //property.SetValue(_t, property.GetValue(convertFrom, null), null);
                }
    
                return _t;
            }
    
            public bool isCollection(object o)
            {
                return o is ICollection
                       || typeof (ICollection<>).IsInstanceOfType(o);
            }
        }
    
    
    public class TransformAttribute : Attribute
        {
            public string RelatedField { get; private set; }
            public string FullyQualifiedName { get; set; }
    
        public TransformAttribute()
        {
        }
    
        public TransformAttribute(string relatedField)
        {
            RelatedField = relatedField;
        }
    
    }
    

    这样最终的结果是:myObject.Transform()

    但是装饰可以让你解释你的 POCO 和你的 ViewModel 之间的差异

    【讨论】:

      猜你喜欢
      • 2023-03-27
      • 2019-05-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-27
      • 1970-01-01
      • 2014-11-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多