8

我已经搜索了 SO 和 Google,但没有找到相关/可接受的答案。
背景:
* 使用 MVC 4.5
* 我在 EF5 之上使用了一些泛型Repo<T>,而这些泛型又由泛型访问Service<T>
* 我有域模型和视图模型,并且我使用 Automapper 在它们之间进行映射,这种映射发生在Service层*最
重要的是,我有我Controllers的尽可能通用的。

所以,对于这个问题;我有几个场景需要向用户展示一个选项列表,他们必须选择一个或多个。这些选项是用户特定的,所以我的域User有一个List<Location>是他们保存的位置,并且在添加/修改时,一个Item, 他们必须至少选择一个Location.

我抵制List<Location>在我的控制器中获取它的诱惑,因为我想让它们保持通用和苗条,但同时,我宁愿在我的ItemView模型中没有两个属性,一个 forAvailableLocations和一个 for SelectedLocations,因为使用了这个模型不仅用于添加/修改,还用于搜索结果等。

选项:
* 我是否应该引入不同的模型来添加/修改一个Item,例如ItemInput
* 我应该使用一些自定义映射并让 Automapper 获取可用位置列表吗?
* 我应该在哪一层获取这些可用位置?

请问人们对这种简洁通用的方法有什么建议?
非常感谢!

4

2 回答 2

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

ps 我从不使用通用服务,我拥有服务的原因是因为它提供的某些数据访问包含不打算与通用 DAL 一起使用的逻辑。

我可以制作一个接口或抽象服务,让我的生活更轻松地进行服务之间的常见操作,但是一旦你定义了一个具体的,UserManagementSerive你肯定是在说你想要管理一个具有用户的对象,以及位置和项目,每个都有它的自己的具体功能?

于 2013-04-30T16:33:51.863 回答
1

我不认为这个问题只有一个可能的答案。

我会推荐一种简单但不那么通用的方法。我会编写所谓的ViewModels,即与您的特定视图相关的模型类。然后我会从控制器获取您的可用位置,并使用获取的位置在您的控制器中填充 ViewModel 的实例。

基本上我会公开一些服务,例如:

IEnumerable<Location> GetAvailableLocationsForUser(string userName);

请注意我用过IEnumerable<T>,不是IQueryable<T>。因为实现实际上会请求数据库,因为如果它是控制器的角色(请记住延迟执行),它太容易出错(至少 IMO IQueryable<T>)。它返回一个域实例,即一个实体,而不是一个映射模型。除了服务层中的域类,我不会亲自处理任何事情。例如,可能存在不是实体的域类,而是实体的组合。这有助于发出有效的请求并避免在控制器中使用延迟加载和延迟执行。当控制器需要整个对象图而不仅仅是一个实体时,这很有帮助。

然后我会在 Web 应用程序程序集中编写如下所示的模型和视图模型:

public LocationModel
{
    ...
}

public CreateItemViewModel : ItemModel
{
    public List<LocationModel> AssociatedLocations { get; set; }
    public List<LocationModel> AvailableLocations { get; set; }
    ...
}
  • 基本上有模型ItemModelLocationModel),它们是与 Web 应用程序相关的对象。这意味着这些模型中可能存在一些与 Web 相关的内容,例如计算的只读属性或属性上的属性(DisplayAttribute...等)。实际上,我会多次编写这些模型,因为我不认为这是可以概括的:例如,一个视图可能需要使用导航属性,而另一个视图则不需要。因此,这会根据使用模型的视图改变映射过程的深度。而且我根本不会使用 AutoMapper(只有手写的映射器)。
  • 还有ViewModels ( CreateItemViewModel),它们是与单个视图相关的对象(例如,本例中允许创建项目的视图)。Model 和 ViewModel 的区别在于 ViewModel 与单个视图相关(并根据该视图命名)。另一方面,模型与多个视图相关(其命名空间有助于了解哪些视图。例如,xxx.Item.Models对于与目录中所有视图相关的模型xxx.Item)。ViewModel 是基于域类在控制器(或单独的映射器)中从头构建的。

在上面的示例中,您可以AssociatedLocations构建一个返回and的域类AvailableLocations,但它需要您的服务层了解 Web 部件(我的意思是,您的服务接口和域类将知道特定视图需要哪些属性)。我不确定这些属性实际上是否与您的应用程序中的单个视图相关,但如果不是这种情况,您还可以构建一个域类作为实体的组合,这些实体将返回AssociatedLocations并且AvailableLocations

public ItemExtended : Item
{
    public List<Location> AssociatedLocations { get; set; }
    public List<Location> AvailableLocations { get; set; }
}

ItemExtended GetItemExtendedById(long idItem);
于 2013-05-02T08:46:13.767 回答