【问题标题】:Creating ViewModels创建 ViewModel
【发布时间】:2015-08-12 16:12:25
【问题描述】:

也许你们中的一些人已经创建了基于洋葱架构的工作应用程序,并且已经解决了我的问题并愿意分享他们的经验。

这就是困扰我的地方。 假设我有超过 100 列的 DomainModel“客户”。 但是对于一个特定的视图,我只需要first and last name for rows meeting some specific conditions

我正在使用存储库/服务模式来公开一些基本的 CRUD 内容。 示例服务

    public class Service<TEntity, TKey> : IService<TEntity, TKey>
        where TEntity : BaseEntity<TKey>
        where TKey : IComparable
    {
        public IUnitOfWork UnitOfWork { get; private set; }
        private readonly IRepository<TEntity, TKey> _repository;
    }

public class CustomerService : Service<Customer,int>, ICustomerService
{
       public ???? GetValidCustomer();
}

现在我有 3 个想法如何处理它,但似乎没有一个是好的。
第一个)在控制器中编写查询

var viewModel = _customerRepository().GetAll().Where(...).Select(...).FirstOrDefault();

我不喜欢这个解决方案,因为它将业务逻辑引入控制器操作,这也可能创建可重复的代码。如果条件发生变化,我将不得不查找整个项目中的所有查询才能更改它们。

2nd) 将视图模型移动到 Service layers
由于Web是洋葱架构的最外层,并且依赖于其他内层,因此我无法重用ViewModel并在Service layers中编写这样的方法,因为不允许循环依赖。

public ValidCustomerViewModel GetValidCustomer()
{
    return _customerRepository().Where(..).Select(new ValidCustomerViewModel() {....} ).FirstOrDefault();
}

同样在服务层创建 ViewModel 似乎不是合适的地方,因为我认为单个服务方法应该能够操作域而不是为视图创建数据(我认为这是 controller 责任)

public ValidCustomerViewModel GetValidCustomer()
{
    var viewModel = new ValidCustomerViewModel();
        viewModel.Customer _customerRepository().Where(..).Select(new ValidCustomerViewModel() {....} ).FirstOrDefault();
    viewModel.Cats = _catRepository.Where(...).ToList();
} //So bad :(

第三次创建 Dto
创建ont to one ViewModel 和 Dto

Inside -> (XXX.Web.Portal.ViewModels.Customer)
public class ValidCustomerViewModel()
{
   [Required]
   public string FirstName {get;set;}
   [Required]
   public string LastName {get;set;}
}

Inside ->(XXX.Core.Dto)
public class ValidCustomerDto
{
    public string FirstName {get;set;}
    public string LastName {get;set;}
}

public ValidCustomerDto GetValidCustomer()
{
    _customerRepository().Where(..).Project().To<ValidCustomerDto>().FirstOrDefault();
}

var dto = _customerServices().GetValidCustomers();
viewModel = Mapper.Map<ValidCustomerModel>(dto);

这会产生一些额外的代码,但它可以修改并且方法返回具体属性。然而,这带来了新的问题...... 现在我可能需要编写类似的方法

public List<ValidCustomerDto> GetValidCustomers()
public PaginatedList<ValidCustomerDto>() GetPaginatedValidCustomersList(...)

第四次返回 IQueryable

    public IQuerable<Customer> GetValidCustomer()
     {
        return _customerRepository.Where(...);
     }

 var viewModel = _customerServices.GetValidCustomer().Project.To<MaValidCustomerViewModel>().FirstOrDefault();

当我写我的问题时,这个想法出现在我的脑海中:) 好吧,这实际上还不错,我看不出有什么重大缺陷。你觉得呢?

非常欢迎所有建议:)

【问题讨论】:

    标签: c# model-view-controller onion-architecture


    【解决方案1】:

    我会选择第四个想法。

    所以它会是这样的:

    服务层:

    public class CustomerService
    {
        public ValidCustomerDto GetValidCustomer()
        {
             _customerRepository.GetValidCustomer().Select(x=> new ValidCustomerDto{ FirstName = x.FirstName, LastName = x.LastName });
        }
    }
    

    作为另一种选择,您可以创建 ReadOnly DbContext 并直接使用它而不是仅用于查询的存储库,这是命令和查询的分离(CQRS 理念)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-20
      相关资源
      最近更新 更多