Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linq 2 Sql - How to design proper repository, controller and view-model flow with entity inheritance

Question: I'm wondering what type of Repository and Controller design/work-flow people implement when using entity inheritance in a ORM, in this case LINQ 2 SQL with MVC .NET.

I have a very simple hierarchy where a Clothing class (concrete) inherits from Product (abstract class). However, this complicates the design quite a bit. It would be foolish to make a repository class per concrete implementation of Product, so I use Product as a parameter type and return type in my 'Product' repository. "However, because of this I must cast the Product type to a concrete implementation of Product (either before requesting from the repository or after).

Another thing I noticed is that even if I determine the correct type to cast to, I have to define my view-models to pass to my view for each concrete implementation of Product.

If this is what needs to be done, so be it, but I'm interested what other people's thoughts and/or experience are.

like image 428
contactmatt Avatar asked Nov 13 '22 21:11

contactmatt


1 Answers

For the sake of this discussion, let's assume your repository interface looks something like:

 public interface IRepository<T>{
     T GetById(int id);
     IQueryable<T> All();
     void Add(T entity);
     void Remove(T entity);
 }

And while you are correct that implementing a repository for each Product type is unnecessary, you could create a generic wrapper class that implements the interface as if it were a dedicated repository. For example,

 public class RepositoryWrapper<T,TBase> : IRepository<T> {
     where T: TBase

     private readonly IRepository<TBase> _repository;
     public RepositoryWrapper(IRepository<TBase> repository){
           _repository = repository;
     }


     public T GetById(int id){
          return (T)_repository.GetById(id);
     }

     public IQueryable<T> All(){
          return _repository.All().OfType<T>();     
     }


     public void Add(T entity){
          _repository.Add(entity);
     }
     public void Remove(T entity){
          _repository.Remove(entity);
     }
 }

Your use case would be a RepositoryWrapper<Clothing,Product>, and you could simplify the creation via an extension method, such as:

public static class SubRepositories{
   public static IRepository<TDerived> GetSubClassRepository<TBase,TDerived>(this IRepository<TBase> repository)
   where TDerived: TBase
   {
       return new RepositoryWrapper<TDerived,TBase>(repository);
   }
}

Now, as far as the view model concern, you don't need to specify the exact type of the view model when passing it in your controller. An alternative is to use templates to automatically determine the type of view to render based on the ModelMetadata.

like image 173
smartcaveman Avatar answered Nov 16 '22 22:11

smartcaveman