存储库中的ViewModels

时间:2017-07-05 12:19:47

标签: c# .net asp.net-mvc design-patterns asp.net-mvc-viewmodel

我已经读过,存储库层不应该处理ViewModel,因为关注点分离,而应该只处理模型。对于服务层也是如此(在我的情况下,这是我的业务逻辑)。那么控制器就可以处理ViewModel的填充。

我有一个模型类别:

public class Category
{

 public int ID { get; set; }

 public int? ParentCategoryID { get; set; }


 public virtual ICollection<Product> Products{ get; set; }

 public virtual ICollection<CategoryName> CategoryNames{ get; set; }
}

我在显示所有类别时使用了ViewModel CategoryListViewModel

public class CategoryListViewModel
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public string ParentName { get; set; }
    }

我的视图采用IEnumerable&lt; ... CategoryListViewModel&gt;

这是我从控制器填充ViewModel的方法:

public ActionResult Index()
        {            
            IEnumerable<CategoryListViewModel> model;
            List<CategoryListViewModel> list = new List<CategoryListViewModel>();
            IEnumerable<Category> categoryList = categoryService.GetAllCategoriesList(RouteData);

            foreach (var item in categoryList)
            {
                CategoryListViewModel temp = new CategoryListViewModel()
                {
                    ID = item.ID,
                    Name = categoryService.GetCategoryName(RouteData, item.ID)                    
                };
                if (item.ParentCategoryID != null)
                {
                    temp.ParentName = categoryService.GetCategoryName(RouteData, (int)item.ParentCategoryID);
                }
                list.Add(temp);
            }
            model = list;
            return View(model);
        }

我的服务方式:

public IEnumerable<Category> GetAllCategoriesList(RouteData data)
        {
            LanguageService languageService = new LanguageService();
            Languages langEnum = languageService.LanguageStringToEnum(languageService.DetermineSelectedLanguage(data));

            IEnumerable<Category> allCategories = repository.getAllCategoriesTest();            

            return allCategories;
        }

public string GetCategoryName(RouteData data, int categoryId)
        {
            LanguageService languageService = new LanguageService();
            Languages langEnum = languageService.LanguageStringToEnum(languageService.DetermineSelectedLanguage(data));
            return repository.GetCategoryName(langEnum, categoryId);
        }

最后我的存储库方法:

public IEnumerable<Category> getAllCategoriesTest()
        {
            return db.Category.ToList();
        }


public string GetCategoryName(Languages lang, int categoryId)
        {
            return db.CategoryName.Where(cn => cn.CategoryID == categoryId && cn.Language == lang).Select(cn => cn.Name).FirstOrDefault();
        }

这种方法对我来说非常糟糕。我的控制器不再薄了,我正在运行很多简单的查询。

如果我在我的存储库中允许ViewModels,我会得到一个更清晰的解决方案。

我的控制器方法:

public ActionResult Index()
        {
            return View(categoryService.GetAllCategories(RouteData));            
        }

服务方式:

public IEnumerable<CategoryListViewModel> GetAllCategories(RouteData data)
        {
            LanguageService languageService = new LanguageService();
            Languages langEnum = languageService.LanguageStringToEnum(languageService.DetermineSelectedLanguage(data));

            return repository.SelectAllCategories(langEnum);
        }

和存储库方法:

public IEnumerable<CategoryListViewModel> SelectAllCategories(Languages lang)
        {                        
            var categories = db.Category.Include(c => c.CategoryNames).Select(names => new CategoryListViewModel
            {
                ID = names.ID,
                Name = names.CategoryNames.Where(cn => cn.Language == lang).Select(cn => cn.Name).FirstOrDefault(),
                ParentName = db.CategoryName.Where(cn => cn.Language == lang && cn.CategoryID == names.ParentCategoryID)
                .Select(cn => cn.Name).FirstOrDefault()
            }).ToList();            
            return categories;                             
        }

这种方法虽然违反了关注点分离,但对我来说似乎更“清洁”。

我的问题是,在查询方面,其他方法不是更有效吗?还有没有其他方法可以这样做,以便不写重型控制器方法,而不是执行那么多的查询?在我看来,我错过了一些东西。

1 个答案:

答案 0 :(得分:2)

首先,请记住,即使它有&#34; MVC&#34;在名称中,ASP.NET MVC只是非常松散地实现了MVC模式。 MVC告诉您有瘦控制器,因为Model是一个活动记录,它处理所有业务逻辑,包括查询自身。这不适用于ASP.NET MVC。在那里,您的模型实际上是您的DAL,服务层,实体和一个或多个视图模型的组合。这意味着控制器不可避免地必须比Ruby on Rails之类的控制器做更多的工作,如果只是将所有这些东西连接在一起。

正如@Liam在上面的评论中建议的那样,你最好的选择是工厂。这样,控制器实际上并不拥有如何将实体映射到视图模型的逻辑。您当然仍然需要在控制器中实际调用工厂,但逻辑仍然是抽象的。

此外,正确的服务层应该汇总逻辑,否则将在您的控制器中。如果您需要类别的本地化名称,则您的服务应该有一个方法,该方法已经返回了具有本地化名称的所有类别。如果您不得不多次点击服务,则表明您尚未为您的应用提供必要的终端。您可能需要引入DTO来处理此数据,因为实体类可能没有适当的属性。然后,您将拥有一个将DTO映射到视图模型的工厂。

最后,对于它的价值,你的存储库是完全没必要的。让您的服务直接与您的Entity Framework上下文交互。拥有一个存储库只需要你购买的其他东西。