3

我问了一个关于在我的控制器中将 ViewModels 映射到实体框架模型的最佳实践的问题,并被告知我的代码是正确的(使用 LINQ 投影),尽管可以另外使用 AutoMapper。

现在我觉得我需要/想要将控制器方法中发生的大部分内容移动到新的服务层,这样我就可以在需要时在该层添加业务逻辑,然后在我的控制器中进行方法调用。但我不确定该怎么做。当然,我的 ViewModel 都将保留在 Web 项目中,那么我在服务层中的方法应该是什么样的以及我在哪里/如何映射 ViewModel?

以下是当前 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();   
        }
    }
4

2 回答 2

5

您的服务层应该返回您的域模型。控制器负责将它们映射到视图模型并将其返回给视图。一个小例子:

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);
}

使用这种方法,您需要一个核心/域层,您的域实体所在的位置。服务层包含业务逻辑并与域模型交互(例如通过存储库)并将物化对象返回给控制器。正如您所建议的,您的视图模型确实应该在网站项目中。

另请查看这个问题,其中我提供了一个类似解决方案的示例。

更新

服务层中的GetLaborarties方法返回一个域模型(集合):

public List<Laboratory> GetLaboratories()
{
    return _db.Laboratories.ToList();
}

现在在您的控制器中调用此方法并将其映射到视图模型。您可以使用 LinqSelect方法执行此操作:

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方法,我要求 Entity Framework 在 sql 查询中包含相关产品。现在Products将包含该类别的所有相关产品。

于 2013-10-17T19:57:40.117 回答
4

我认为将这种简单的代码重构到另一层是没有意义的,但是这个问题在其他情况下是有意义的,在这些情况下会发生更复杂的处理,例如,您创建一个帐户,为其设置默认密码并分配角色这使得在单个业务事务中的插入很少,并且可能很少选择。

服务层由服务组成。您的服务在域实体级别运行。

public class AccountService
{
    private PASSEntities _context { get; set; }

    public AccountService( PASSEntities context )
    {
       this._context = context;
    }

    public User CreateAccount( string username, string password )
    {
       // implementation here
    }

您从控制器访问服务,这是视图模型和模型之间发生转换的地方,因此服务不知道视图模型层:

[HttpPost]
public ActionResult CreateUser( UserViewModel model )
{
   using ( PASSEntities context = new PASSEntities() )
   {
      AccountService service = new AccountService( context );
      service.CreateUser( model.Username, model.Password );

      // return something appropriate here     
   }
}
于 2013-10-17T19:53:21.263 回答