views:

73

answers:

2

Hi everyone!
I'm building web shop in ASP.NET MVC.
I have two entities: Category and Product.

One product can belong to one or more categories.

On webpage, user can see a list of categories. By clicking category name, he can see all products in that category. User may also search products by name, category, price, etc.

Controllers
Which actions should I put in the Category controller and which actions should I put in the Product controller?

Repositories
Do I need two repositories (one for each entity) and if I do, which methods belong to which repository:

IList<Category> GetCategories();
IList<Product> GetProducts(int categoryId);
Product GetProductById(int productId);
IList<Product> GetProducts(string name, decimal? minPrice, decimal? maxPrice);

Thank you for your help!

A: 

If the action gives you back categories, put it in the Category controller. If it gives you back products put it in the Product controller. Same goes for the repositories.

That's simplistic, but I think it works in your case.

Tim
+1  A: 

Application structure and design is largely a matter of preference. There are a lot of ways to do it right and a lot of ways to do it wrong. I'll write up what I would do and you can take it for what it's worth...

I like to have 1 simple data access repository for each object or table in my database. I usually have those repositories implement a simple generic interface. I then build a "Service" or "Provider" of sorts that implements each of those simple interfaces and bring all the functionality of an "aggregate" into one place. By "aggregate" I mean a group of classes and objects that all share a similar function (ie Blog, Shop, Logging, etc). I'm constantly looking for a better way to handle this but this is a rough estimate of the classes and interfaces I would use for this:

// interfaces
IRepository<T>
IProductRepository : IRepository<Product>
ICategoryRepository : IRepository<Category>
IShopService

// concrete implementations
LinqToSqlProductRepository : IProductRepository
LinqToSqlCategoryRepository : ICategoryRepository
ShopService : IShopService

As for what actions methods to put on your controllers? I rarely find a scenario where a basic RESTful approach doesn't work. There isn't much you CAN'T do with a Add, List, Show, Delete/Destroy, Edit action.

// example ProductController
Add()
Add(ProductAddModel)
Delete(int id)
Edit(int id)
Edit(ProductEditModel)
List(int page)
Show(int id)

EDIT:

After taking a look I changed the signature of:

IShopService : IProductRepository, ICategoryRepository

to:

IShopService

The reason being that since I'm using a generic interface behind both the IProductRepository and ICategoryRepository, when you go to implement the IShopService you'll have multiple Add(), Delete(), FindAll(), FindByID(), etc. methods; with only their parameters being different.

A better approach is to just have the IShopService interface alone and have the concrete implementation of that interface work with a IProductRepository and an ICategoryRepository.

DM
I somehow don't like the approach with generics in repository architecture because it locks your "sub"repositories to the same set of methods, while I usually end up with some different methods across different entities. But if one only has Add(), Delete(), Update() methods in repository then I guess it works. Other than that, nice answer.
mare
@DM, I'm going with DDD approach, and that's why I only gave you interfaces. If I need to return the 'Category' and all 'Products' within that category, do I have to put this method in 'CategoryRepository' or 'ProductRepository'?
šljaker
@mare My IRepository<T> class is pretty basic with only 5 or 6 methods to implement. I typed my response up on the fly and noticed something that wasn't right. See edit for clarification.
DM
@sljaker In that scenario I'd ask the ICategoryRepository for a Category, and do so from inside my IShopService. Your concrete implementation of the IShopService should would with a IProductRepository and an ICategoryRepository for it's data access. Workflow: Your web app needs a Category... It calls the FindCategory(int id) method from your IShopService... The concrete implementation of your IShopService calls and returns _categoryRepositry.FindByID(id)...
DM
@DM, Thank you.
šljaker