我问了一个关于在控制器中将ViewModels映射到Entity Framework模型的最佳实践的问题,并被告知我的代码是正确的(使用LINQ投影),尽管还可以使用AutoMapper。
现在,我觉得我需要/想要将Controller方法中发生的大部分操作移至新的Service层,以便可以在需要时在该层添加业务逻辑,然后在控制器中进行方法调用。但是我不确定该怎么做。我的ViewModels都将保留在Web项目中,因此服务层中的方法应该是什么样子以及在何处/如何映射ViewModels?
这是当前GET和POST控制器方法的示例:
public ActionResult Laboratories()
{
var context = new PASSEntities();
var model = (from a in context.Laboratories
select new LaboratoryViewModel()
{
ID = a.ID,
Description = a.Description,
LabAdmins = (from b in context.Users_Roles
join c in context.Users on b.User_ID equals c.ID
where b.Laboratory_ID == a.ID
select new LabAdminViewModel()
{
ID = b.ID,
User_ID = b.User_ID,
Role_ID = b.Role_ID,
Laboratory_ID = b.Laboratory_ID,
BNL_ID = c.BNL_ID,
First_Name = c.Pool.First_Name,
Last_Name = c.Pool.Last_Name,
Account = c.Account
})
});
return View(model);
}
[HttpPost]
public ActionResult AddLaboratory(LaboratoryViewModel model)
{
try
{
using (PASSEntities context = new PASSEntities())
{
var laboratory = new Laboratory()
{
ID = model.ID,
Description = model.Description
};
context.Laboratories.Add(laboratory);
context.SaveChanges();
}
return RedirectToAction("Laboratories");
}
catch
{
return View();
}
}
最佳答案
您的服务层应返回您的域模型。控制器负责将它们映射到视图模型并将其返回到视图。一个小例子:
public ActionResult Laboratories()
{
// Get the laboratories domain models from the service layer.
var laboratories = _laboratoryService.GetLaboratories();
// Map the domain models to view models using AutoMapper.
var laboratoriesModel = Mapper.Map<List<LaboratoryViewModel>>(laboratories);
// Return view model to the view.
return View(laboratoriesModel);
}
使用这种方法,您需要一个域域所在的核心/域层。服务层包含业务逻辑,并与域模型进行交互(例如,通过存储库),并将物化对象返回给控制器。正如您所建议的,您的视图模型确实应该在“网站”项目中。
还要检查this question,其中提供了类似解决方案的示例。
更新资料
服务层中的
GetLaborarties
方法返回一个(或多个)域模型:public List<Laboratory> GetLaboratories()
{
return _db.Laboratories.ToList();
}
现在,在控制器中,您调用此方法并将其映射到视图模型。您可以使用Linq
Select
方法执行此操作:public ActionResult Laboratories()
{
// Get the laboratories domain models from the service layer.
var laboratories = _laboratoryService.GetLaboratories();
var laboratoriesModel = laboratories.Select(new LaboratoryViewModel
{
// Map here..
}).ToList();
return View(laboratoriesModel);
}
或使用如上所述的AutoMapper。
更新2
具有相关对象导航属性的简单示例:
假设我们有这个领域模型:
public class Category
{
public string Name { get; set; }
public string UrlName { get; set; }
// Other properties..
public virtual ICollection<Product> Products { get; set; }
}
我们可以在服务层中创建一个方法:
public CategoryService : ICategoryService
{
public Category GetByName(string name)
{
return _categoryRepository.Table
.Include(c => c.Products) // Include related products
.FirstOrDefault(c => c.UrlName = name);
}
}
我将实体框架配置为类别包含零个或多个产品。使用
Include
方法,我要求实体框架在sql查询中包括相关产品。现在,Products
将包含该类别的所有相关产品。