Sam
Sam

Reputation: 15770

ASP.NET MVC - I think I am going about this wrong

Or I don't understand this at all.

I have started my ASP.NET MVC application using the Controller --> ViewModel --> Service --> Repository pattern.

Does every type of object (Customer, Product, Category, Invoice, etc..) need to have it's own repository and service? If so, how do you bring common items together?

I mean there are a lot of the times when a few of these things will be displayed on the same page. So I am not getting this I don't think.

So I was thinking I need a ShopController, which has a ShopViewModel, which could have categories, sub categoires, products, etc. But the problem, for me, is that it just does not seem to mesh well.

Maybe ASP.NET WebForms were for people like me :)

Edit

So would an aggregate consist of say:

Category, SubCategory, Product, ChildProduct, ProductReview with the Product being the aggregate root?

Then in the ViewModels, you would access the Product to get at it's child products, reviews, etc.

I am using entity framework 4, so how would you implement lazy loading using the repository/service pattern?

Upvotes: 2

Views: 189

Answers (3)

Mark Coleman
Mark Coleman

Reputation: 40863

Does every type of object (Customer, Product, Category, Invoice, etc..) need to have it's own repository

You should have a repository per aggregate root in your domain. See this question for more information on what is an aggregate root.

In the example you give I could see a CustomerReposiotry which would handle retrieve all pertinent customer data(Customer has orders a order has a customer). A ProductRepository that handles retrieving product information.

and service? If so, how do you bring common items together?

A service layer is nice but only if there is added value in adding this layer. If your service simply passes straight into the repository it might not be needed. However if you need to perform certain business logic on a Product a ProductService might make sense.

This might not make sense

public void UpdateProduct(Product product)
{
  _repo.Update(product);
}

But if you have logic this layer makes sense to encapsulate your business rules for products.

public void UpdateProduct(Product productToUpdate)
{
  //Perform some sort of business on the productToUpdate, raise domain events, ....
  _repo.Update(productToUpdate);
}

So I was thinking I need a ShopController, which has a ShopViewModel, which could have categories, sub categoires, products, etc. But the problem, for me, is that it just does not seem to mesh well.

If the domain is flushed out the view model ends up making sense

public ActionResult Index()
{
  ShopViewModel shopViewModel = new ShopViewModel();
  shopViewModel.Products = _productRepo.GetAll();
  //other stuff on the view model.
  return(shopViewModel);
}

Update

What happens when you also need to provide data unobtainable from an aggregate root? For example, say I have a create Customer view and in that view, I also need to provide the user with a collection of Companies to choose from to associate a new customer with. Does the collection of Companies come from CustomerRepository or would you also need a CompanyRepository?

If a Company can live by itself (e.g. you edit, update, delete a company) I would suggest a Company is also an aggregate root for your domain (A Customer has a company and a company has a list of Customers). However if a Company is only obtainable via a Customer, I would treat a company as a ValueType/Value Object. If that is the case I would create a method on the customer repository to retrive all CompanyNames.

_repo.GetAllCompanyNames();

Upvotes: 6

jenson-button-event
jenson-button-event

Reputation: 18961

Repositories are indispensable, just go with them. They hide out data implementation. Used with an ORM you can pretty much forget about core db activity (CRUD). You'll find generally there's 1:1 map between an object and a repository, but nothing stops a repository returning anything it likes. Typically though you will acting upon an instance. Create non-object specific repositories for your queries that don't naturally fit into an existing one.

You will find a lot of conflicting arguments on the "Services" part of it - which some people like to split between Domain Services (i'd call these business rules that don't comfortably fit into a Core Domain Object) and Application Services (logical groupings of operations on Domain Objects). I've actually gone for one, separate project called [ProjectName].Core.Operations that lives in my [ProjectName].Core solution folder. Core + Operations = Domain.

An operation might be something that returns a DTO of all the information a View requires built via a number of repository calls and actions on the Domain. Some people (myself included) prefer to hide Repositories completely from Presentation and instead use Operations(Services) as a facade to the them. Just go with gut feeling on naming and don't be afraid, refactoring is healthy. Nothing wrong with a HomePageOperations class, with a method GetEveryThingINeedForTheHomepage returns a ThingsINeedForTheHomePage class.

Keep your controllers as light weight as possible. all they do is map data to views and views to data, talk to "Services" and handle application flow.

Download and have a look at S#arp architecture or the Who Can Help Me projects. The latter really shows a good architecture IMHO.

Lastly don't forget one of the major concerns of tiers is pluggability/testability, so I advise getting your head around a good IoC container (I'm a fan of Castle.Windsor). Again S#arp architecture is a good place to find about this.

Upvotes: 4

Russ Cam
Russ Cam

Reputation: 125538

You can pass more than one type of Repository to the controller (I'm assuming your using some kind of IoC container and constructor injection). You may then decide to compose some type of service object from all of the passed repositories.

Upvotes: 1

Related Questions