MVC: Как работать с сущностями со многими дочерними сущностями? - PullRequest
9 голосов
/ 31 мая 2009

В текущих примерах ASP.NET MVC я вижу довольно простые сущности с простыми методами CRUD.
Но я не уверен, что делать с более продвинутыми моделями. Позвольте мне привести пример:

У нас есть гаражный сайт. В гараже есть:

  • Инвентарь с carparts
  • Employees
  • Customers
  • Cars, который состоит из всех автомобилей, которые находятся / находились в гараже

Теперь давайте возьмем car, автомобиль может иметь коллекцию employees, которая работала над автомобилем (происходит от оригинального класса employee, добавляет несколько дополнительных предметов, которые привязывают его к машине), коллекцию carparts, которые были заменены (также производные, добавляет, например, SerialNr и ReplacementDate prop), и, конечно, customer prop клиента, которому принадлежит автомобиль.

Сейчас в 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

Так как бы мне построить свои контроллеры? Должен ли я добавить все эти методы CRUD для дочерних элементов в CarsController? Разве это не делает очень толстый контроллер из-за десятков методов (эта модель чрезмерно упрощена, у машины гораздо больше родительско-дочерних отношений)? Или я должен создать EmployeesInCar контроллер (кажется, плохо) ... Большое спасибо.

EDIT:
Прежде всего, пример только гипотетический, просто пример.
Если я последую этому предложению, у меня будет CarController, который обрабатывает только автомобили. И мой PartsController будет обрабатывать только части. Но у нас есть два набора Part с, общий (для инвентаря); и у нас есть Part внутри автомобиля, который является производным от общего, но добавляет такие свойства, как SerialNumber и ReplacementDate.
Так что мой контроллер Parts становится довольно толстым, для примера давайте назовем сущности: GeneralPart (в инвентаре) и SpecificPart (производный класс с дополнительными свойствами)

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

Потому что каждое действие имеет дело с Общей Частью или Определенной Частью. То же самое относится и к сотрудникам, у нас есть базовый класс сотрудников и определенный класс с дополнительными свойствами.

Ответы [ 5 ]

1 голос
/ 31 мая 2009

Ваша сущность "CarPart" (класс CarPartModel) может находиться в состоянии "сток" (класс StockCarPartModel: CarPartModel) или в состоянии "заменено" (класс ReplacedCarPartModel: CarPartModel). Тогда:

  • GET для / carpart / index должен возвращать все сущности (CarPartModel)
  • GET для / carpart / replace должен вернуть замененные детали (ReplacedCarPartModel)
  • GET для / carpart / bycar / {id} должен вернуть детали, связанные с конкретным автомобилем (ReplacedCarPartModel)
  • GET для / carpart / инвентарь должен вернуть запчасти на складе (StockCarPartModel)

Все это обрабатывается маршрутом "по умолчанию", и в вашем CarPartController вы можете выполнить следующие действия:

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

Я думаю, что ваш контроллер не толстый. Для контроллера нормально иметь дело с наследованием модели. Основная сложность будет в ваших ViewModels и Views

1 голос
/ 31 мая 2009

Ваш дизайн должен изначально фокусироваться на объектах. У вас есть car, employees и inventory. Напишите контроллер для каждого из них. Это даст вам основные маршруты:

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

Отсюда вы сможете написать новый маршрут с пользовательским ограничением маршрута со следующей структурой:

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

Это также немного лучше, чем /cars/{id}/carpart/{id}, потому что слово car в carpart является избыточным. /car/.../part/ указывает, что деталь предназначена для автомобиля.

Думать о подобных вещах для дизайна URI очень важно на раннем этапе, потому что изменение дизайна URI позже нарушит индексы, закладки и ссылки в поисковых системах.

1 голос
/ 31 мая 2009

Если вы хотите использовать типы путей, которые вы указали в своем примере, похоже, вы должны научиться использовать механизм маршрутизации в .NET 3.5. Вы должны иметь возможность использовать типы URL, которые вам нужны, но вам нужно будет создать несколько пользовательских маршрутов и, возможно, собственный обработчик маршрутов, чтобы выполнить это. Механизм маршрутизации в .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

Ваши маршруты будут соответствовать вашим шаблонам URL и превращать их в правильный маршрут к вашему контроллеру, принимая идентификаторы и сопоставляя их с параметрами ваших действий.

РЕДАКТИРОВАТЬ 3:

Итак, теперь, когда я понимаю ваш вопрос более полно, я надеюсь, что смогу ответить на него лучше. Вообще говоря, я думаю, что контроллеры должны отображать 1: 1 с вашими сущностями. Если у вас есть GeneralPart, то у вас должен быть контроллер, предназначенный для управления общими частями. Если у вас есть CarPart, у вас должен быть контроллер, предназначенный для управления автомобильными деталями. Если CarParts - это GeneralParts, и в некоторых случаях они могут вести себя как GeneralParts, то, вероятно, лучше иметь эти аспекты управления на GeneralPartsController, если только это управление не имеет дело с какими-либо специальными атрибутами CarPart ... в этом случае управление должно быть делегировано CarPartsController. Довольно элегантно то, как полиморфизм играет роль в организации контроллеров, и как отношение «является» позволяет вам повторно использовать контроллеры для управления несколькими типами.

Если честно, у вас есть довольно сложный сценарий, с которым я непосредственно не сталкивался при работе с ASP.NET MVC. Я стараюсь по возможности избегать таких сценариев, потому что они порождают сложные вопросы, подобные этим, которые, как правило, субъективны в своих ответах. В конечном счете, вы должны организовать свои контроллеры таким образом, чтобы иметь логический смысл того, как они используются, как они сопоставляются с вашими сущностями, и насколько хорошо они организуют поведение, которое вы заинтересованы представить. Иногда не логично отображать все ваши контроллеры в один объект. Иногда вам нужен «составной» контроллер, который обрабатывает действия, которые работают с несколькими объектами одновременно, или графики объектов. В этих случаях, вероятно, лучше всего иметь контроллеры, выделенные для этих конкретных групп поведения, а не пытаться найти один специфичный для сущности контроллер, который «подходит».

0 голосов
/ 05 марта 2011

Я бы порекомендовал использовать Restful Routing для ASP .NET MVC:

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

0 голосов
/ 31 мая 2009

Вам не нужно, чтобы в контроллере происходило слишком много вещей.
Думайте о контроллере как о классе, который определяет, что пользователь хочет и что он должен увидеть в конце.

То, что хочет пользователь, определяется подсистемой ASP.NET MVC автоматически для вас с помощью маршрутов, определенных в файле Global.asax. Затем контроллер должен решить, какой вид должен видеть пользователь в результате запроса, который он / она сделал.

Так что для вашего приложения все будет примерно так:

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
    }

}

Так что, в принципе, именно так вы бы настроили свой контроллер (и) для такого приложения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...