我已经读到,存储库层不应该因为关注点的分离而处理ViewModels,而应该只处理模型。对于服务层也是如此(在我的例子中,这就是我的业务逻辑所在)。因此,控制器被留给处理ViewModels的总体。
我有一个模型类别:
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<...CategoryListViewModel>
我是这样从控制器中填充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;
}这种方法,虽然违反了分离的关注,似乎是“更清洁”对我。
我的问题是,在查询方面,另一种方法不是更有效吗?此外,还有其他方法可以避免编写大量控制器方法而不执行那么多查询吗?在我看来,我好像错过了什么。
发布于 2017-07-05 13:10:23
首先,请记住,尽管名称中有" MVC“,ASP.NET MVC只是非常松散地实现MVC模式。MVC告诉您要有瘦控制器,因为模型是一个活动记录,它处理所有业务逻辑,包括围绕查询本身的业务逻辑。这不适用于ASP.NET MVC。在那里,您的模型实际上是DAL、服务层、实体和一个或多个视图模型的组合。这意味着,如果只将所有这些东西连接在一起,控制器就必须完成至少比Rails之类的控制器多一点的工作。
正如@Liam在上面的评论中所建议的,你最好的选择是工厂。这样,控制器实际上并不拥有如何将实体映射到视图模型的逻辑。当然,您仍然需要实际调用控制器中的工厂,但是逻辑仍然是抽象的。
另外,适当的服务层应该卷起本来在控制器中的逻辑。如果您需要该类别的本地化名称,则您的服务应该有一个方法,该方法将返回所有类别及其本地化名称。如果您必须多次访问您的服务,这就清楚地表明您没有为您的应用程序提供必要的端点。您可能需要引入一个DTO来处理这些数据,因为实体类可能没有适当的属性。然后,您将拥有一个将DTO映射到视图模型的工厂。
最后,对于它的价值,您的存储库是完全没有必要的。只需让您的服务直接与实体框架上下文交互即可。拥有一个存储库不会给您带来任何东西,只会给您额外的维护。
https://stackoverflow.com/questions/44926123
复制相似问题