谁填充了ASP MVC 5中的ViewModel

agg*_*gie 9 c# asp.net-mvc entity-framework viewmodel

谁负责填充ASP MVC 5架构(C#,EF)中的值,例如,如果我们有 PurchaseRecordsViewModel , PurchaseRecords Domain Model , PurchaseController

  • 填充数据的代码(时间,成本等)是否为viewmodel,就在它自己的viewmodel中进入PurchaseRecordsViewModel

  • 或者,代码是否在Action的Action方法中 PurchaseController

Tom*_*mmy 12

视图模型通常只是属性的愚蠢集合.填充视图模型通常位于服务层内部,如果没有,则采用操作方法.

以这种方式考虑角色.

  • 域模型是到数据库表的直接映射.
  • 视图模型是显示视图所需的属性的集合.
  • 服务层获取/使用一个或多个域模型并填充视图模型.
  • 服务层还可以采用视图模型并创建/更新一个或多个域模型
  • 控制器动作方法是两者之间的粘合剂.它调用服务层来获取(GET)视图模型并将其传递给视图.这些操作方法还采用(POST)视图模型并将其传递给服务层,以执行需要对其执行的任何操作.

通常问的另一个问题是为什么我不能将域模型用于视图?您可以,但通常会遇到类似这样的问题,需要来自多个域模型的数据,不需要域模型中的所有属性,最后,您现在必须担心在您的域模型上更新属性不打算.

  • @DarthVader - 实际上,我见过的大多数 MVC 应用程序都使用服务层(业务层)。无论如何,我在这里使用“服务”层作为示例来展示如何使用和填充域模型和视图模型。你是对的,视图模型在哪里生成并不重要。然而,这里的许多例子以及其他地方(http://codebetter.com/iancooper/2008/12/03/the-fat-controller/)都警告不要使用“胖”控制器。 (2认同)

CSh*_*per 8

扩展Tommy的答案,这里有一些代码与他的描述一致.

//Controller

public ActionResult Index()
{
  List<OrderViewModel>() model = new List<OrderViewModel>();  
  model = new ServiceClass().GetOrders();

  return View(model);
}

//here is your Service Class, this layer transfers the Domain Model into your ViewModel
public List<OrderViewModel> GetOrders()
{
   List<OrderDomain> model = new List<OrderDomain>();

   model = new DataAccess().GetOrders();

   List<OrderViewModel> viewModel = new List<OrderViewModel>();

   foreach (var order in model)
   {
        OrderViewModel vm = new OrderViewModel();
        vm.OrderId = order.OrderId;
        vm.OrderName = order.OrderName;

        viewModel.Add(vm);
   }      

    return viewModel;        
}

//some DataAccess class, this class is used for database access

Public List<OrderDomain> GetOrders()
{
     List<OrderDomain> model = new List<OrderDomain>();

      using (var context = new MyEntities())
      {
          model = (from x in context.Order
                   select new OrderDomain
                   {
                     OrderId = x.OrderId,
                     OrderName = x.OrderName
                   }).ToList();                     
      }
   return model;
}
Run Code Online (Sandbox Code Playgroud)

编辑:这似乎是一个温和的流行答案,所以我想提一下我不再遵循这种模式.相反,我一直在使用mediatr和垂直切片架构.

  • 由于Web应用程序依赖于服务层,因此无法从服务层返回Web应用程序中定义的模型.您需要定义此模型,无论您想要将其称为服务和Web项目都可以访问的模型. (2认同)

Mic*_*ael 7

理想情况下,PurchaseRecordViewModel应该通过获取来填充自己PurchaseRecordsDomainModel.它应该包含属性的简单映射,并且可能包含您将在视图中使用的输出的某些格式.

PurchaseRecordsViewModel

public class PurchaseRecordsViewModel
{
   public IEnumerable<PurchaseRecordViewModel> PurchaseRecords {get;set;}
}
Run Code Online (Sandbox Code Playgroud)

PurchaseRecordViewModel

 public class PurchaseRecordViewModel
 {
    public DateTime Date {get;set;}
    public decimal Cost {get;set;}
    // .... some other properties
    public PurchaseRecordsViewModel(PurchaseRecordsDomainModel domainModel)
    {
       Date = domainModel.Date;
       Cost = domainModel.Cost;
       // .... some other property mappings
    }
 }
Run Code Online (Sandbox Code Playgroud)

你的action方法上PurchaseController应该做的,是策划让你的过程中PurchaseRecordsDomainModel,创造PurchaseRecordsViewModelPurchaseRecordsDomainModel并将它传递给了View.Action方法本身不应包含任何处理从数据库连接和检索数据的代码(在您的情况下查询EF上下文)或任何业务逻辑.您应该尝试使用松散耦合的模块,通过相互通信abstractions,这样您将确保您的应用程序是maintainable,extensibletestable.

此外,尝试在系统的各个层之间绘制清晰的分隔.例如,拥有EF entitiesas 不是一个好主意Domain Model Entites.您不希望您business logic layer依赖data access layer,以这种方式考虑,如果在将来的某个时间点,您正在远离EF并使用其他ORM甚至其他技术来存储和查询数据.你不想business logic layer因为改变你的想法而改变data access layer.所以在你的情况下从单词到代码.

考虑到你已经有你viewview model我将创建PurchaseRecordsServicedomain layer(请注意:根据你的情况,你可能不会使用Repositories,但其它一些技术,这个例子主要是为了说明我的观点)

public class PurchaseRecordsService
{
   private readonly IPurchaseRecordsRepository _purchaseRecordsRepository;
   public PurchaseRecordsService(IPurchaseRecordsRepository purchaseRecordsRepository)
   {
      if(purchaseRecordsRepository == null)
      {
         throw new ArgumentNullException("purchaseRecordsRepository");
      }

      _purchaseRecordsRepository = purchaseRecordsRepository;
   }

   public IEnumerable<PurchaseRecordsDomainModel> GetPurchaseRecords()
   {
      // trivial case, real code can be more complex
      return _purchaseRecordsRepository.GetPurchaseRecords();
   }
}
Run Code Online (Sandbox Code Playgroud)

然后在你的domain layer,你可以定义IPurchaseRecordsRepository

public interface IPurchaseRecordsRepository
{
   IEnumerable<PurchaseRecordsDomainModel > GetPurchaseRecords();
}
Run Code Online (Sandbox Code Playgroud)

我们的想法是,我们PurchaseRecordsService需要一种与数据库进行通信的方式,因此无论谁使用它,都必须提供实现IPurchaseRecordsRepository.下一步是移动到我们的data access layer创建实现类IPurchaseRecordsRepository.

public class EfPurchaseRecordsRepository: IPurchaseRecordsRepository
{
   private readonly EfObjectContext _objectContext;
   public EfPurchaseRecordsRepository(string connectionString)
   {
      _objectContext = new EfObjectContext(connectionString);
   }

   public IEnumerable<PurchaseRecordsDomainModel > GetPurchaseRecords()
   {
      var purchaseRecords = (from p in _objectContext.PurchaseRecords
                            ....
                            select p).AsEnumerable();

      return purchaseRecords .Select(p => p.ConvertToDomainPurchaseRecord());
   }
}
Run Code Online (Sandbox Code Playgroud)

最后一块 - 我们需要定义我们Action的内容PurchaseController

public class PurchaseController: Controller
{
   private readonly IPurchaseRecordsRepository _repository;

   public PurchaseController(IPurchaseRecordsRepository repository)
   {
      if(repository == null)
      {
         throw new ArgumentNullException("repository");
      }
      _repository = repository;
   }

   public ActionResult Index()
   {
      var purchaseRecordsService = new PurchaseRecordsService(_repository);

      var purchaseRecordsViewModel = new PurchaseRecordsViewModel();

      var purchaseRecords = purchaseRecordsService.GetPurchaseRecords();

      foreach(var purchaseRecord in purchaseRecords)
      {
          var purchaseRecordViewModel = new PurchaseRecordViewModel(purchaseRecord);
          purchaseRecordsViewModel.PurchaseRecords.Add(purchaseRecordViewModel);
      }

      return View(purchaseRecordsViewModel);
   }
}
Run Code Online (Sandbox Code Playgroud)

回顾一下,我们所拥有的是松散耦合的代码,我们PresentationData AccessLayers彼此不了解,并且它们仅依赖于Domain层.如果需要,可以替换MVC前端WPF,例如,从EF另一种技术转移,您的代码是可测试的.

  • 这三个都是很好的答案帮助..我也喜欢C Shaper的回复......但你有一个详细的样本! (2认同)