Your controllers (in the MVC project) should be calling your objects in the Service project. The services project is where all the business logic is handled.
A good example is this:
public ActionResult Index()
{
ProductServices productServices = new ProductServices();
// top 10 products, for example.
IList<Product> productList = productServices.GetProducts(10);
// Set this data into the custom viewdata.
ViewData.Model = new ProductViewData
{
ProductList = productList;
};
return View();
}
or with Dependency Injection (my fav)
// Field with the reference to all product services (aka. business logic)
private readonly ProductServices _productServices;
// 'Greedy' constructor, which Dependency Injection auto finds and therefore
// will use.
public ProductController(ProductServices productServices)
{
_productServices = productServices;
}
public ActionResult Index()
{
// top 10 products, for example.
// NOTE: The services instance was automagically created by the DI
// so i din't have to worry about it NOT being instansiated.
IList<Product> productList = _productServices.GetProducts(10);
// Set this data into the custom viewdata.
ViewData.Model = new ProductViewData
{
ProductList = productList;
};
return View();
}
Now .. what's the Service project (or what is ProductServices)? that's a class library with your business logic. For example.
public class ProductServices : IProductServices
{
private readonly ProductRepository _productRepository;
public ProductServices(ProductRepository productRepository)
{
_productRepository = productRepository;
}
public IList<Product> GetProducts(int numberOfProducts)
{
// GetProducts() and OrderByMostRecent() are custom linq helpers...
return _productRepository.GetProducts()
.OrderByMostRecent()
.Take(numberOfProducts)
.ToList();
}
}
but that might be all so hardcore and confusing... so a simple version of the ServiceProduct class could be (but i wouldn't really recommend) ...
public class ProductServices
{
public IList<Product> GetProducts(int numberOfProducts)
{
using (DB db = new Linq2SqlDb() )
{
return (from p in db.Products
orderby p.DateCreated ascending
select p).Take(10).ToList();
}
}
}
So there you go. You can see that all the logic is in the Service projects, which means u can reuse that code in other places.
Where did i learn this?
From Rob Conery's MVC StoreFront media and tutorials. Best thing since sliced bread.
His tutorials explain (what i did) in good detail with full solution code examples. He uses Dependency Injection which is SOO kewl now that i've seen how he uses it, in MVC.
HTH.
The main point of a repository (as in Single Responsibility Principle) is to abstract the concept of getting objects that have identity. As I've become more comfortable with DDD, I haven't found it useful to think about repositories as being mainly focused on data persistence but instead as factories that instantiate objects and persist their identity.
When you're using an ORM you should be using their API in as limited a way as possible, giving yourself a facade perhaps that is domain specific. So regardless your domain would still just see a repository. The fact that it has an ORM on the other side is an "implementation detail".
Best Answer
You've actually raised a question here that's currently generating a lot of discussion in the developer community - see the follow-up comments to Should my repository expose IQueryable?
The repository can - and should - create complex combination objects containing multiple associated entities. In domain-driven design, these are called aggregates - collections of associated objects organized into some cohesive structure. Your code doesn't have to call
GetCustomer()
,GetOrdersForCustomer()
,GetInvoicesForCustomer()
separately - you just callmyCustomerRepository.Load(customerId)
, and you get back a deep customer object with those properties already instantiated. I should also add that if you're returning individual objects based on specific database tables, then that's a perfectly valid approach, but it's not really a repository per sé - it's just a data-access layer.On one hand, there is a compelling argument that Linq-to-SQL objects, with their 'smart' properties and their deferred execution (i.e. not loading Customer.Orders until you actually use it) are a completely valid implementation of the repository pattern, because you're not actually running database code, you're running LINQ statements (which are then translated into DB code by the underlying LINQ provider)
On the other hand, as Matt Briggs' post points out, L2S is fairly tightly coupled to your database structure (one class per table) and has limitations (no many-many mappings, for example) - and you may be better off using L2S for data access within your repository, but then map the L2S objects onto your own domain model objects and return those.