在ASP MVC 5体系结构(C#,EF)中填充值的责任是什么?如果我们有PurchaseRecordsViewModel , PurchaseRecords Domain Model , PurchaseController
填充数据的代码(时间,成本等)是否与viewmodel一致,就在它自己的viewmodel中进入PurchaseRecordsViewModel
?
或者,代码是否采用PurchaseController
答案 0 :(得分:11)
查看模型通常只是属性的愚蠢集合。填充视图模型通常位于服务层内部,如果没有,则采用操作方法。
以这种方式思考角色。
通常会问的另一个问题是为什么我不能将域模型用于视图?您可以,但通常会遇到类似这样的问题,需要来自多个域模型的数据,不需要域模型中的所有属性,最后,您现在必须担心在您的域模型上更新属性不打算。
答案 1 :(得分:8)
根据汤米的回答,这里有一些代码可以与他的描述一致。
//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;
}
编辑: 这似乎是一个温和的流行答案,所以我想提一下我不再遵循这种模式。相反,我一直在使用mediatr和垂直切片架构。
答案 2 :(得分:7)
理想情况下,PurchaseRecordViewModel
应该通过获取PurchaseRecordsDomainModel
来填充自己。它应该包含属性的简单映射,以及可能在视图中使用的输出格式。
<强> PurchaseRecordsViewModel 强>
public class PurchaseRecordsViewModel
{
public IEnumerable<PurchaseRecordViewModel> PurchaseRecords {get;set;}
}
<强> 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
}
}
action
PurchaseController
方法应该做什么,正在协调从PurchaseRecordsDomainModel
获取PurchaseRecordsViewModel
,创建PurchaseRecordsDomainModel
并将其传递给View
的过程Action
。 EF
方法本身不应包含任何处理从数据库连接和检索数据的代码(在您查询abstractions
上下文的情况下)或任何业务逻辑。你应该尝试使用松散耦合的模块,通过maintainable
相互交谈,这样你就可以确保你的应用程序是extensible
,testable
和EF entities
。
此外,尝试在系统的各个层之间绘制清晰的分隔。例如,将Domain Model Entites
设为business logic layer
不是一个好主意。你不希望你的data access layer
依赖EF
,以这种方式思考,如果在将来的某个时候,你正在远离ORM
和使用其他business logic layer
甚至其他技术来存储和查询数据。您不想仅仅因为您正在更改data access layer
而更改view
。所以在你的案例中从单词转到代码。
考虑到您已经拥有view model
和PurchaseRecordsService
,我会在domain 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();
}
}
但是,其他一些技巧,这个例子主要是为了说明我的观点)
domain layer
然后在IPurchaseRecordsRepository
中,您可以定义public interface IPurchaseRecordsRepository
{
IEnumerable<PurchaseRecordsDomainModel > GetPurchaseRecords();
}
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());
}
}
。
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);
}
}
Presentation
总结一下,我们所拥有的是松散耦合的代码,我们的Data Access
和Domain
图层彼此之间并不了解,而且它们仅依赖于MVC
图层。如果需要,您可以将WPF
前端替换为EF
,例如,从{{1}}移至另一项技术,您的代码可以测试。
答案 3 :(得分:3)
理想情况下,您的视图模型应该不知道您的域模型,所以我要说您将人口逻辑放在控制器中,可能包含在某种映射/填充实用程序类中。
但请记住,当涉及到将某些逻辑置于何处的问题时,个人偏好会有很长的路要走。