我问了一个关于在控制器中将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将包含该类别的所有相关产品。

09-11 20:14