MVC:如何使用具有许多子实体的实体?

时间:2009-05-31 07:03:03

标签: asp.net-mvc

在ASP.NET MVC的当前示例中,我看到了非常基本的实体,使用简单的CRUD方法 但我不确定如何处理更高级的模型。让我举个例子:

我们有一个车库网站。车库有:

  • 使用carparts
  • 的广告资源
  • Employees
  • Customers
  • Cars由车库中的所有车辆组成

现在让我们来看car,汽车可能有一个employees的集合在汽车上工作(从原来的employee类派生,添加一些额外的道具,将他绑定到汽车),已被替换的carparts集合(也派生,添加例如SerialNr和ReplacementDate道具),当然还有客户的customer道具。车。

现在在rest我希望看到以下内容:

/cars/423 [get]                  //show car # 423
/cars/423/edit [get]             //shows the edit form (ajax enabled, so also shows the other props)
/cars/423/carparts [get]          //gets the carparts inside the car
/cars/423/carparts/32/edit [post] //updates that specific carpart inside the specific car
/cars/423/employees [get]         //gets the employees who worked on the car
/inventory [get]
/inventory/1234/edit [get]        //gets the update form for carpart with ID 1234                   
/employees [get]                  //gets all the employees in the company

那么我将如何构建我的控制器?我应该为CarsController中的子元素添加所有这些CRUD方法吗?由于数十种方法(这种模式过于简化,汽车有更多的亲子关系),这不是一个非常胖的控制器吗?或者我应该创建一个EmployeesInCar控制器(看起来很糟糕)...... 非常感谢。

修改
首先,这个例子只是假设,只是一个例子 如果我遵循这个建议,我会有CarController只处理汽车。我的PartsController只处理Parts。但是我们有两组Part s,一组一般(用于库存);我们在汽车内部有一个Part,它来自一般汽车,但增加了SerialNumberReplacementDate等属性。 所以我的部件控制器变得非常胖,例如让我们调用实体:GeneralPart(在库存中)和SpecificPart(派生类,具有额外的属性)

Index -> Returns all GeneralParts in inventory.
IndexByCar(int id) -> Return all SpecificParts by Car.
etc. etc.

因为每个动作都涉及一般部分或特定部分。对于员工来说也是如此,我们有基础员工类,以及具有额外属性的特定员工类。

5 个答案:

答案 0 :(得分:1)

如果您希望使用示例中提供的各种路径,那么您应该学习如何在.NET 3.5中使用路由引擎。您应该能够使用您需要的各种网址,但是您需要创建多个自定义路由,并且可能需要一个自定义路由处理程序来完成它。 .NET 3.5中的路由引擎非常灵活,并非专为MVC设计......它实际上非常通用,可以提供非常广泛的,可能是无限范围的URL重写。

我住的地方有点晚了,所以我试图写的例子并没有形成。 :P可以说,自定义路由处理程序和一些新的路由映射应该可以帮助您获得所需的位置。

编辑:这可能有所帮助:

http://codingcockerel.co.uk/2008/05/26/custom-routing-for-asp-net-mvc/

编辑2: 我之前遗漏了控制器。路由只是让您能够使用所需的URL类型。这是一件好事...你提出的URL类型将提供更好的长期SEO体验。至于组织控制器,我建议保持简单:

/Controllers/CarsController.cs
/Controllers/PartsController.cs
/Controllers/EmployeesController.cs
/Controllers/InventoryController.cs

您的路线将与您的网址模式相匹配,并将其转换为与您的控制器相关的正确路线,获取ID并将其与您的操作参数相匹配。

编辑3:

所以,既然我更充分理解你的问题,我希望我能更好地回答它。一般来说,我认为控制器应该与您的实体进行1:1的映射。如果您有GeneralPart,那么您应该有一个专用于管理通用部件的控制器。如果你有CarPart,那么你应该有一个专门用于管理汽车零件的控制器。如果CarParts是GeneralParts,并且在某些情况下它们的行为类似于GeneralParts,那么最好在GeneralPartsController上具有这些管理方面,除非该管理处理CarPart的任何特殊属性...在这种情况下应该委派管理到CarPartsController。多态性如何影响控制器组织,以及“是一种”关系如何允许您重用控制器来管理多种类型。

说实话,你有一个相当复杂的场景我在使用ASP.NET MVC时没有直接遇到过。我尽量避免这种情况,因为它们会引起像这样的复杂问题,这些问题在答案中往往是主观的。最终,您应该以一种逻辑意义来组织您的控制器,使其具有使用方式,它们如何映射到您的实体,以及它们如何组织您感兴趣的行为。有时,将所有控制器映射到单个实体是不合逻辑的。有时您需要一个“复合”控制器来处理同时对多个实体进行操作的操作,或实体图。在这些情况下,最好将控制器专用于那些特定的行为组,而不是试图找到一个特定于实体的控制器“sorta fits”。

答案 1 :(得分:1)

您的设计应该首先关注实体。您有caremployeesinventory。为每一个写一个控制器。这将为您提供基本路线:

  • /cars/{action}/{id}
  • /employees/{action}/{id}
  • /inventory/{action}/{id}

从这里开始,您应该可以使用custom route constraint编写一个具有以下结构的新路线:

/cars/{id}/part/{id}/

这也比/cars/{id}/carpart/{id}略好,因为carpart中的单词car是多余的。 /car/.../part/表示该部分适用于汽车。

为URI设计考虑这些问题在早期非常重要,因为稍后更改URI设计会破坏搜索引擎索引,书签和链接。

答案 2 :(得分:1)

您的“CarPart”实体(类CarPartModel)可以处于“stock”状态(类StockCarPartModel:CarPartModel)或“已替换”状态(类ReplacedCarPartModel:CarPartModel)。然后:

  • GET到/ carpart / index应该返回所有实体(CarPartModel)
  • GET to / carpart / replacement应该返回更换的部分(ReplacedCarPartModel)
  • 获取/ carpart / bycar / {id}应返回与特定汽车相关的零件(ReplacedCarPartModel)
  • 获取/ carpart / inventory应返回库存中的零件(StockCarPartModel)

这一切都由“默认”路线处理,在你的CarPartController中你有行动:

public ActionResult Index() { ... }
public ActionResult Replaced() { ... }
public ActionResult ByCar(string carId) { ... }
public ActionResult Inventory() { ... }

我认为你的控制器并不胖。控制器处理模型继承是正常的。主要的复杂性将出现在ViewModels和Views

答案 3 :(得分:0)

您不需要在控制器中进行太多操作 将控制器视为一个类,用于确定用户想要什么以及最终应该看到什么。

在您使用Global.asax文件中定义的路由的帮助下,ASP.NET MVC引擎会自动确定用户想要什么。然后,控制器应决定用户应该看到的视图,以及他/她做出的请求。

因此,对于您的应用程序,事情将会是这样的:

Global.asax中

routes.MapRoute("Cars", "cars/{id}/{action}",
    new { controller = "Cars", action = "Details", id = "" } );
//This route should give you the URLs you listed on your question

CarsController.cs

public class CarsController : Controller {

    //this action will be called for URLs like "/cars/423"
    //or /cars/423/details
    public ActionResult Details(int id) {
         //You would most likely have a service or business logic layer
         //which handles talking to your DAL and returning the objects 
         //that are needed for presentation and likes
         Car car = SomeClass.GetCar(id);
         if (car == null) {
             //if there's no car with the ID specified in the URL
             //then show a view explaining that
             return View("CarNotFound");
         }
         //if there's a car with that ID then return a view that
         //takes Car as its model and shows details about it
         return View(car);
    }

    //this action will be called for URLs like /cars/423/edit
    [AcceptVerbs(HttpVerbs.Get)]
    public ActionResult Edit(int id) {
        //again get the car, show an edit form if it's available for editing
    }

    //this action will be called for URLs like /cars/423/edit too
    //but only when the request verb is POST
    [AcceptVerbs(HttpVerbs.Post), ActionName("Edit")]
    public ActionResult Save(int id) {
        //save the changes on the car, again using your business logic layer
        //you don't need the actual implementation of saving the car here
        //then either show a confirmation message with a view, 
        //saying the car was saved or redirect the user to the 
        //Details action with the id of the car they just edited
    }

}

所以基本上这就是你为这样的应用程序设置控制器的方法。

答案 4 :(得分:0)

我建议使用Restful Routing for ASP .NET MVC:

https://github.com/stevehodgkiss/restful-routing