Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC: How to work with entities with many child entities?

Tags:

asp.net-mvc

In the current examples on ASP.NET MVC I see quite basic entities, with simple CRUD methods.
But I'm not sure about what to do with more advanced models. Let me give an example:

We have a garage website. The garage has:

  • Inventory with carparts
  • Employees
  • Customers
  • Cars that consists of all cars that are/were in the garage

Now lets take the car, the car might have a collection of employees that worked on the car (derived from the original employee class, adds some extra props that tie him to the car), a collection of carparts that have been replaced (also derived, adds for example SerialNr, and ReplacementDate prop) , and of course a customer prop of the customer whoe owns the car.

Now in rest I would like to see the following:

/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

So how would I build my Controllers? Should I add all those CRUD methods for the child elements inside the CarsController? Doesn't that make a very fat controller because of the tens of methods (this model is overly simplified, the car has many more parent-child relationships)? Or should I create a EmployeesInCar controller (seems bad)... Thanks a lot.

EDIT:
First of all the example is hypothetical only, just an example.
If I follow the suggestion I would have a CarController which only handles cars. And my PartsController would handle only Parts. But we have two sets of Parts, a general one (for the inventory); and we have a Part inside a car, which derives from the general one, but adds properties such as SerialNumber and ReplacementDate.
So my Parts controller becomes quite fat, for the example let's call the entities: GeneralPart (in inventory) and SpecificPart (the derived class, with the extra properties)

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

Because each action deals with either a General Part or a Specific Part. The same is for employees, we have the base employee class, and a specific one, with extra properties.

like image 703
Gideon Avatar asked May 31 '09 07:05

Gideon


3 Answers

If you wish to use the kinds of paths you provided in your example, then it sounds like you should learn how to use the Routing engine in .NET 3.5. You should be able to use the kinds of urls you need, but you will need to create several custom routes and probably a custom route handler to accomplish it. The Routing engine in .NET 3.5 is very flexible and was not designed specifically for MVC...its actually very generic and can provide a very broad, probably unlimited range of url rewriting.

Its a bit late where I live, so the example I was trying to write just isn't forming. :P Suffice to say, a custom route handler and some new route mappings should get you where you need to be.

EDIT: This may be of help:

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

EDIT 2: I left out controllers before. The routing just gets you the ability to use the kinds of URLs you want. And thats a good thing...the kinds of URL's you proposed will provide a better SEO experience long-term. As for organizing your controllers, I recommend keeping it simple:

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

Your routes would match your url patterns, and turn them into a proper route to your controller, taking the ID's and matching them to the parameters of your actions.

EDIT 3:

So, now that I understand your question more fully, I hope I can answer it better. Generally speaking, I think controllers should map 1:1 with your entities. If you have a GeneralPart, then you should have a controller dedicated to managing general parts. If you have CarPart, then you should have a controller dedicated to managing car parts. If CarParts are GeneralParts, and they can behave like GeneralParts in some cases, then it is probably best to have those management aspects on the GeneralPartsController, unless that management deals with any special attributes of a CarPart...in which case management should be delegated to CarPartsController. It is kind of elegant how polymorphism plays into controller organization, and how the "is a" relationship allows you to reuse controllers to manage multiple types.

To be honest, you have a fairly complex scenario I havn't directly encountered in my time working with ASP.NET MVC. I try to avoid such scenarios as much as possible, because they give rise to complicated questions like this that tend to be subjective in their answers. Ultimately, you should organize your controllers in a way that makes logical sense to how they are used, how they map to your entities, and how well they organize the behavior you are interested in exposing. Sometimes, it isn't logical to map all of your controllers to a single entity. Sometimes you need to have a "composite" controller that deals with actions that operate on multiple entities at once, or graphs of entities. In these cases, its probably best to have controllers dedicated to those particular behavioral groups, rather than trying to find one entity-specific controller that "sorta fits".

like image 110
jrista Avatar answered Nov 06 '22 16:11

jrista


Your design should initially focus on the entities. You have car, employees and inventory. Write a controller for each one of these. That will give you the basic routes:

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

From here you should be able to write a new route with a custom route constraint with the following structure:

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

This is also slightly better than /cars/{id}/carpart/{id} because the word car in carpart is redundant. /car/.../part/ indicates that part is for a car.

Thinking about things like these for URI design is really important early on because changing the URI design later will break search engine indices, bookmarks and links.

like image 39
aleemb Avatar answered Nov 06 '22 15:11

aleemb


Your "CarPart" entity (class CarPartModel) can be in "stock" state (class StockCarPartModel : CarPartModel) or "replaced" state (class ReplacedCarPartModel : CarPartModel). Then:

  • GET to /carpart/index should return all entities (CarPartModel)
  • GET to /carpart/replaced should return replaced parts (ReplacedCarPartModel)
  • GET to /carpart/bycar/{id} should return parts, related to specific car (ReplacedCarPartModel)
  • GET to /carpart/inventory should return parts in stock (StockCarPartModel)

This all is handled by "Default" route and in your CarPartController your have actions:

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

I think your controller is not fat. It is normal for controller to deal with Model inheritance. The main complexity will be in your ViewModels and Views

like image 1
eu-ge-ne Avatar answered Nov 06 '22 17:11

eu-ge-ne