【问题标题】:Is there a shortcut to convert a model to a view model?是否有将模型转换为视图模型的快捷方式?
【发布时间】:2016-09-12 21:00:16
【问题描述】:

我是 C# 和 .NET 的新手。我正在学习 ASP.NET MVC 5。我发现自己花了额外的时间将模型转换为视图模型。

这是我的模型

public class Overview
{

    public string chain_name { get; set; }
    public int store_id { get; set; }
    public int total_attempts { get; set; }
    public int total_unique_number_called { get; set;  }
    public int total_callable { get; set; }
    public int total_completed_interviews { get; set; }

}

这是我的视图模型

public class OverviewViewModel
{

    public string chain_name { get; set; }
    public int store_id { get; set; }
    public int total_attempts { get; set; }
    public int total_unique_number_called { get; set; }
    public int total_callable { get; set; }
    public int total_completed_interviews { get; set; }
    public decimal? unique_number_per_complete { get; set; }

    public OverviewViewModel()
    {
        unique_number_per_complete = 0;
    }

}

正如您所见,Model 和 ViewModel 是相同的,除了 over variable 是一个计算。

要填充我的视图模型,我执行以下操作

var records = conn.Database.SqlQuery<Overview>(query).ToList();

var overView = new List<OverviewViewModel>();

foreach(var record in records){

    var newRecord = new OverviewViewModel();

    newRecord.store_id = record.store_id;

    newRecord.chain_name = record.chain_name;

    newRecord.total_attempts = record.total_attempts;

    newRecord.total_callable = record.total_callable;

    newRecord.total_completed_interviews = record.total_completed_interviews;

    if (record.total_completed_interviews > 0) {
        newRecord.total_unique_number_called = record.total_unique_number_called / record.total_completed_interviews;
    }

    overView.Add(newRecord);
}

我在我的方法中看到的两个问题是

  1. 我必须做很多额外的编码,尤其是视图模型很大或者我有多个变量需要计算。
  2. 我觉得我要多循环 1 次才能将模型转换为查看模式。

在 c# 中有更简单的方法吗?

对于大型应用程序,此过程是否有更好的方法?我的目标是学习更好的方法来充分利用我的代码时间。

【问题讨论】:

  • AutoMapper 可以帮助进行简单的映射。
  • 请注意,Automapper 非常慢,如果您有大量数据 tp 处理,请考虑自己的自定义映射器 [link]stackoverflow.com/questions/4131720/…

标签: c# asp.net .net asp.net-mvc asp.net-mvc-5


【解决方案1】:

我同意您应该研究 automapper,但另一种方法是在您的 OverviewViewModel 模型上创建一个构造函数,该构造函数采用 Overview 对象并填充所有属性。类似的东西

public class OverviewViewModel {

    public string chain_name { get; set; }
    public int store_id { get; set; }
    public int total_attempts { get; set; }
    public int total_unique_number_called { get; set; }
    public int total_callable { get; set; }
    public int total_completed_interviews { get; set; }
    public decimal? unique_number_per_complete { get; set; }

    public OverviewViewModel()
    {
        unique_number_per_complete = 0;
    }
public OverviewViewModel(Overview record)
    {
        store_id = record.store_id;

    chain_name = record.chain_name;

    total_attempts = record.total_attempts;

    total_callable = record.total_callable;
    //etc
    }
}  

那么你的代码会是这样的

var overView = new List<OverviewViewModel>();

foreach(var record in records){
    overView.Add(new OverViewViewModel(record));
}

【讨论】:

  • +1 非常好!我会毫不犹豫地考虑到这一点。但首先我喜欢让自动映射器工作,因为它似乎是最好的方法
  • 我还认为在该构造函数中使用自动映射器可以很好地缩短我的代码,而不必列出每个可能变长的变量。
【解决方案2】:

是的,你应该使用 Automapper,安装包视图 Nuget。 Automapper 也非常可配置。

http://automapper.org/

首先,创建这个类:

public static class AutoMapperConfig
{
    public static void RegisterMappings()
    {
        //Example here, creates "two way" for Overview & OverviewViewModel mapping
        Mapper.CreateMap<Overview, OverviewViewModel>(); //<source, destination>
        Mapper.CreateMap<OverviewViewModel, Overview>(); //<source, destination>
        //..more mapping for other Models and ViewModels.
    }
}

在 Global.asax.ApplicationStart() 中添加这一行:

AutoMapperConfig.RegisterMappings()

现在您在 cmets 中的 foreach 示例非常简单:

foreach (var record in records)
{
    var newRecordOverviewViewModel = Mapper.Map<OverviewViewModel>(record); //<destination>(source)
    overView.Add(newRecordOverviewViewModel);
}

【讨论】:

  • 非常感谢布赖恩。我刚刚在我的项目中安装了 AutoMapper。我试图通过将我的 Overview 对象转换为 OverviewViewModel 对象来使用。如果这真的是我需要的,我会接受你的回答。我不确定您是否有一个简短的代码可以用来转换这两个对象,但是如果您这样做,那将对我有很大帮助。谢谢你:)
  • 您介意帮助我了解语法吗?这就是我所做的,但我正在尝试映射foreach(var record in records){ OverviewViewModel newRecord = new OverviewViewModel(); var config = new MapperConfiguration(cfg =&gt; cfg.CreateMap&lt;record, newRecord&gt;()); var mapper = config.CreateMapper(); var final = mapper.Map&lt;newRecord&gt;(record); overView.Add(final); } 的 2 个对象中读取卷曲的行
  • 现在处理语法,我可以告诉你,你不要像你正在做的那样在 foreach 循环中创建 MapperConfiguration,你只需在 Global.asax 中做一次。将为您更新答案。
  • @MikeA 用代码检查我的答案更新,如果您有任何问题,请告诉我,Automapper 非常棒,正是您想要做的事情。
  • 非常感谢您的帮助。在这里我应该提到的一件事是,当我使用这种声明 AutoMapper.Mapper.CreateMap... is obsolete: Dynamically creating maps will be removed in version 5.0. Use a Mapper Configuration instance and store statically as needed, or mapper.Initilize. Use CreateMapper to create a mapper instance 的方法时,我收到了一条警告。
【解决方案3】:

另一种选择是使用如下的 Linq 和扩展方法

using System.Collections.Generic;
using System.Linq;
using App.Data.Entities;
using App.Business.Models;

namespace App.Business
{
    public static partial class OverviewAdapter
    {
        public static OverviewViewModel ToOverviewViewModel(this Overview overview)
        {
            return new OverviewViewModel
            {
                chain_name                  =   overview.chain_name,
                store_id                    =   overview.store_id,
                total_attempts              =   overview.total_attempts,
                total_unique_number_called  =   overview.total_unique_number_called,
                total_callable              =   overview.total_callable,
                total_completed_interviews  =   overview.total_completed_interviews,
                unique_number_per_complete  =   0
            };
        }

        public static IEnumerable<OverviewViewModel> ToOverviewModelList(this IEnumerable<OverviewViewModel> overviewList)
        {
            return (overviewList != null) ? overviewList.Select(a => a.ToOverviewViewModel()) : new List<OverviewViewModel>();
        }

        // Reverse - ToOverview / ToOverviewList if needed...
   }
}

现在,只要您的 Business 类在范围内,您就会在该类上拥有一个 可发现 方法以及可以内联添加的类列表。

var records = conn.Database.SqlQuery<Overview>(query).ToOverviewModelList().ToList();

这种更实用的方法是直观的、流线型的,如果尚未编写适配器,您可以立即获得反馈。

从列表版本返回 IEnumerable 还是 List 是个人偏好。更广泛的 IEnumerable 是更传统的解决方案,但我倾向于一直从 List 转到 List 并且下降到 IEnumerable 似乎是多余的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-20
    • 1970-01-01
    • 2014-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多