EDIT
Should i put service layer and repository layer into one project, so the web project is able to reference to DbContext objects ? Now my web(controllers) are unable to reference to dbcontext objects. what is the right way?
// service and repository are together
(View <- Controller) -> (Service -> Repository -> EF DbContext) -> (DB)
// separate service and repository layer
(View <- Controller) -> (Service) -> (Repository -> EF DbContext) -> (DB)
Below are original question
i know SO is an excellent community to post my questions about mvc design patterns. Please give me your advice and I will appreciate your help. Thank you!
We are planning for a new project and our priority is to develop an application that is extensible and loosely-coupled.
I am new to software development; I did some reading on MVC Music Store Tutorial, and followed by a book called Pro ASP.NET MVC 3 Framework by Steven Sanderson (Apress),From the book, I learnt about DDD(Domain driven design) and some other concepts like repository and dependency injection. I have followed the book to build the SportsStore website, and gained some basic understanding about DI. But I personally think that the example did not separate the business logic layer, so i did a research on that, i found a pattern called Service Layer Pattern, and from what i understand, it separates the Business logic layer. Based on this, I came out with a structure for my new project(sample project below).
Do i need to implement IDisposable interface? if yes, where and why? Is this structure feasible for a relatively big-scale project?
sample database design: Product(one)----(many)ProductCategoryRs(many)----(one)Category
the solution contains 3 projects: Repository,Service,Web
Repository:
Define IRepository interface , basic CRUD operations
Are these signatures sufficient? Should I add TEntity GetById(object id);?
public interface IRepository<TEntity>
{
IQueryable<TEntity> All { get; }
void Create(TEntity item);
void Update(TEntity item);
void Delete(TEntity item);
void SaveChanges();
}
Implement generic Repository class
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
STOREEntities context;
public Repository()
{
context = new STOREEntities();
}
public IQueryable<TEntity> All
{
get
{
return context.Set<TEntity>();
}
}
public void Create(TEntity item)
{
context.Set<TEntity>().Add(item);
}
public void Update(TEntity item)
{
context.Entry<TEntity>(item).State = System.Data.EntityState.Modified;
}
public void Delete(TEntity item)
{
context.Set<TEntity>().Remove(item);
}
public void SaveChanges()
{
context.SaveChanges();
}
}
Service: Define IProductService interface, extend business logic here.
public interface IProductService
{
IEnumerable<Product> Products { get; }
IEnumerable<Product> Get(Expression<Func<Product, Boolean>> filter);
Product GetByProductId(int productId);
void AddProduct(Product product);
void EditProduct(Product product);
void RemoveProduct(Product product);
void SaveChanges();
}
Implement Product Service
public class ProductService : IProductService
{
IRepository<Product> repository; //Inject
public ProductService(IRepository<Product> repo)
{
repository = repo;
}
public IEnumerable<Product> Products
{
get { return repository.All; }
}
public IEnumerable<Product> Get(Expression<Func<Product, bool>> filter)
{
return repository.All.Where(filter);
}
public Product GetByProductId(int productId)
{
return repository.All.SingleOrDefault(p => p.ProductID == productId);
}
public void AddProduct(Product product)
{
repository.Create(product);
}
public void EditProduct(Product product)
{
repository.Update(product);
}
public void RemoveProduct(Product product)
{
repository.Delete(product);
}
public void SaveChanges()
{
repository.SaveChanges();
}
}
Web project, retrieve data from service and convert to viewmodel and display. ProductController code
public class ProductController : Controller
{
IProductService productService; //inject
public ProductController(IProductService service)
{
productService = service;
}
public ActionResult Index()
{
var products = productService.Products; //retrieve from service layer
return View(products);
}
}
I believe you really should add a TEntity GetById(int id)
to your IRepository<TEntity>
generic interface.
Why? Because if you don't, and if you want to fetch a single record on your business layer, you only have two options (on the repository, data-access layer):
IQueryable<TEntity>
, which, yes, will allow you to get a single record from the database, but may cause a lot of nasty side-effects.The first option is clearly wrong. The second is controversial, but (unless your project has you as a single developer, and you really really really know what you're doing) it is potentially leaky and unsafe. So, if you do need a single record (and sometimes you'll surely do), expose a method that does exactly that.
Having said that, you should also not expose IQueryable<TEntity> All { get; }
, for exactly the same reasons above. Use IEnumerable<TEntity> All { get; }
instead, and make your concrete generic repository class return a real collection, by calling context.Set<TEntity>().ToList()
for instance.
Edit
Regarding IDisposable:
There are only two (related) reasons for implementing the IDisposable interface that I can think of:
In your case, you probably should use it on your repository implementation. Please take a look at this SO question for further information.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With