我已经搜索了SO和Google,但没有找到相关/可接受的答案
背景:
*使用MVC 4.5
*我在EF5的顶部使用了一些Generic Repo<T>
,后者又通过Service<T>
进行访问
*我有域模型和视图模型,我使用Automapper在它们之间进行映射,这种映射发生在Service
层中
*最重要的是,我的Controllers
也是尽可能通用的。{
那么,对于这个问题;我有几个场景,我需要向用户提供一个选项列表,他们必须选择一个或多个。这些选项是特定于用户的,因此我的域User
有List<Location>
这是他们保存的位置,在添加/修改Item
时,他们需要选择至少一个Location
1}}。
我正在抵制在我的控制器中获取List<Location>
的诱惑,因为我想让它们保持通用和纤薄,但与此同时,我在ItemView
模型中没有两个属性,一个用于AvailableLocations
,一个用于SelectedLocations
,因为此模型不仅用于添加/修改,还用于搜索结果等。
选项:
*我是否应该引入一个不同的模型来添加/修改Item
,例如ItemInput
?
*我应该使用一些自定义映射并获取Automapper来获取可用位置列表吗?
*我应该在哪一层获取这些可用的位置?
关于这个问题的整洁和通用方法,人们的建议是什么?
非常感谢!
答案 0 :(得分:2)
我会做这样的事情:
public IEnumerable<Location> GetLocations() {
return db.GetAll();
}
然后在你的控制器里面(我从MVC脚手架跟着这个):
ViewBag.Locations = new SelectList(service.GetLocations, "name", "id");
(或您自己的复选框列表) 并在HTML / View页面上放置一个列表控件。
我认为这是最好的方法的原因是因为逻辑都存在于服务中。如果你把它放在你的DTO /数据模型中,你可能会遇到这个问题:
如果您需要额外的逻辑来撤回位置,会发生什么?即地点的子位置。
您更改服务(或覆盖)以反映新的更改,此逻辑将进入服务内部:
public IEnumerable<Location> GetLocations(string parent) {
return db.GetAll().Where(loc => loc.parentname = parent);
}
P.S。我从不使用通用服务,我有一个服务的原因是因为它提供的一些数据访问包含的逻辑并不适用于通用DAL。
我可以创建一个接口或抽象服务,使我的生活对于服务之间的常见操作更容易一些,但是一旦你定义了具体的,UserManagementSerive
肯定你说要管理一个拥有用户的对象,以及每个都有自己特定功能的位置和项目?
答案 1 :(得分:1)
我认为这个问题只有一个可能的答案。
我会推荐一种简单但不那么通用的方法。我会写出所谓的 ViewModels ,即与特定视图相关的模型类。然后我将从控制器获取您的可用位置,并使用获取的位置在控制器中填充ViewModel的实例。
基本上我会公开一些服务,如:
IEnumerable<Location> GetAvailableLocationsForUser(string userName);
请注意我使用的是IEnumerable<T>
,而不是IQueryable<T>
。因为实现实际上会请求数据库,因为它太容易出错(至少是IMO),如果它是控制器的角色(记住IQueryable<T>
的延迟执行)。
它返回一个域实例,即实体,而不是映射模型。除了服务层中的域类,我不会亲自处理任何事情。可能存在不实体的域类,但是例如实体的组合。这有助于提高请求并避免在控制器中使用延迟加载和延迟执行。当控制器需要整个对象图而不仅仅是实体时,这很有用。
然后我会在Web应用程序程序集中编写如下所示的Models和ViewModel:
public LocationModel
{
...
}
public CreateItemViewModel : ItemModel
{
public List<LocationModel> AssociatedLocations { get; set; }
public List<LocationModel> AvailableLocations { get; set; }
...
}
ItemModel
和LocationModel
),它们是与Web应用程序相关的对象。这意味着在这些模型中可能存在一些与Web相关的事物,例如计算的只读属性或属性上的属性(DisplayAttribute
...等)。
实际上,我会多次编写这些模型,因为我不认为这是可以推广的东西:例如,一个视图可能需要使用导航属性而另一个视图则不需要。因此,这会根据使用模型的视图更改映射过程的深度。我根本不会使用AutoMapper(只有手写的映射器)。CreateItemViewModel
),它们是与单个视图相关的对象(例如,允许在此创建项目的视图例)。 Model和ViewModel之间的区别在于ViewModel与单个视图相关(并根据此视图命名)。另一方面,模型与多个视图相关(其名称空间有助于了解哪些视图。例如,xxx.Item.Models
用于与xxx.Item
目录中的所有视图相关的模型。 ViewModel是基于域类在控制器(或单独的映射器)中从头开始构建的。在上面的示例中,您可以构建一个返回AssociatedLocations
和AvailableLocations
的域类,但这需要您的服务层了解Web部件(我的意思是,您的服务接口和域类将知道特定视图需要哪些属性)。我不确定这些属性是否与应用程序中的单个视图实际相关,但如果不是这样,您还可以将域类构建为将返回AssociatedLocations
和{{1}的实体组合。 }:
AvailableLocations