title: Entity framework, abstract class, generic repository and generic manager
body: <p>In a project, we use generic repository and generic manager so we don't need to rewrite every update / delete etc method in every repository / manager.</p>
  
  <p>Here is how they looks :</p>
  
  <pre><code>public interface IBaseRep&lt;T&gt; : IDisposable where T : class, PrivateObject
  {
      DbSet&lt;T&gt; DatabaseSet { get; set; }
      DbContext Dal { get; set; }
  
      T Find(int? id);
      T Find(Expression&lt;Func&lt;T, bool&gt;&gt; predicate);
      ICollection&lt;T&gt; Select(Expression&lt;Func&lt;T, bool&gt;&gt; predicate = null,
          Expression&lt;Func&lt;T, string&gt;&gt; orderBy = null,
          string includeProperties = "");
      T Create(T obj);
      T Update(T obj);
      bool Delete(T obj);
      bool Delete(int id);
      bool Delete(Expression&lt;Func&lt;T, bool&gt;&gt; predicate);
      IQueryable&lt;T&gt; SelectAsQuery(
          Expression&lt;Func&lt;T, bool&gt;&gt; predicate = null, 
          Expression&lt;Func&lt;T, string&gt;&gt; orderBy = null, 
          string includeProperties = "");
  }
  
  public class BaseRep&lt;T&gt; : IBaseRep&lt;T&gt; where T : class, PrivateObject
  {
      public DbSet&lt;T&gt; DatabaseSet { get; set; }
      public DbContext Dal { get; set; }
  
      public EORTCBaseRep(DbContext dal)
      {
          this.Dal = dal;
          this.DatabaseSet = Dal.Set&lt;T&gt;();
      }
  
      public virtual T Find(int? id)
      {
          return this.DatabaseSet.Find(id);
      }
  
      public virtual T Find(Expression&lt;Func&lt;T, bool&gt;&gt; predicate)
      {
          return Select(predicate).FirstOrDefault();
      }
  
      public virtual ICollection&lt;T&gt; Select(
          Expression&lt;Func&lt;T, bool&gt;&gt; predicate = null,
          Expression&lt;Func&lt;T, string&gt;&gt; orderBy = null,
          string includeProperties = "")
      {
          return SelectAsQuery(predicate, orderBy, includeProperties).ToList();
      }
  
      public virtual IQueryable&lt;T&gt; SelectAsQuery(
         Expression&lt;Func&lt;T, bool&gt;&gt; predicate = null,
         Expression&lt;Func&lt;T, string&gt;&gt; orderBy = null,
         string includeProperties = "")
      {
          IQueryable&lt;T&gt; query = this.DatabaseSet;
  
          if (predicate != null)
              query = query.Where(predicate);
  
          foreach (var includeProperty in includeProperties.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
              query = query.Include(includeProperty);
  
          if (orderBy != null)
              query = query.OrderBy(orderBy);
  
          return query;
      }
  
      public virtual T Create(T obj)
      {
          this.Dal.Entry&lt;T&gt;(obj).State = EntityState.Added;
          this.Dal.SaveChanges();
          return obj;
      }
  
      public virtual T Update(T obj)
      {
          this.Dal.Entry&lt;T&gt;(obj).State = EntityState.Modified;
          this.Dal.SaveChanges();
          return obj;
      }
  
      public virtual bool Delete(T obj)
      {
          if (obj is ILogicallyDeletable)
          {
              this.Dal.Entry&lt;T&gt;(obj).State = EntityState.Modified;
              (obj as ILogicallyDeletable).IsDeleted = true;
          }
          else
          {
              this.Dal.Entry&lt;T&gt;(obj).State = EntityState.Deleted;
          }
          return this.Dal.SaveChanges() == 1;
      }
  
      public virtual bool Delete(int id)
      {
          T obj = Find(id);
          return Delete(obj);
      }
  
      public virtual bool Delete(Expression&lt;Func&lt;T, bool&gt;&gt; predicate)
      {
          foreach (T item in Select(predicate))
          {
              Delete(item);
          }
          return this.Dal.SaveChanges() == 1;
      }
  
      public virtual void Dispose()
      {
          this.Dal.Dispose();
      }
  }
  </code></pre>
  
  <p>Our managers looks like this :</p>
  
  <pre><code>public interface IBaseManager&lt;T&gt; : IDisposable where T : class, PrivateObject
  {
      T Find(int? id);
      T Find(Expression&lt;Func&lt;T, bool&gt;&gt; predicate);
      ICollection&lt;T&gt; Select(Expression&lt;Func&lt;T, bool&gt;&gt; predicate = null,
          Expression&lt;Func&lt;T, string&gt;&gt; orderBy = null,
          string includeProperties = "");
      T Create(T obj);
      T Update(T obj);
      bool Delete(T obj);
      bool Delete(int id);
      bool Delete(Expression&lt;Func&lt;T, bool&gt;&gt; predicate);
      IQueryable&lt;T&gt; SelectAsQuery(
          Expression&lt;Func&lt;T, bool&gt;&gt; predicate = null,
          Expression&lt;Func&lt;T, string&gt;&gt; orderBy = null,
          string includeProperties = "");
  }
  
  public class BaseManager&lt;T&gt; : IBaseManager&lt;T&gt; where T : class, PrivateObject
  {
      protected IBaseRep&lt;T&gt; Repository;
  
      public virtual T Find(int? id)
      {
          return this.Repository.Find(id);
      }
  
      public virtual T Find(Expression&lt;Func&lt;T, bool&gt;&gt; predicate)
      {
          return this.Repository.Find(predicate);
      }
  
      public virtual ICollection&lt;T&gt; Select(
          Expression&lt;Func&lt;T, bool&gt;&gt; predicate = null,
          Expression&lt;Func&lt;T, string&gt;&gt; orderBy = null,
          string includeProperties = "")
      {
          return this.Repository.Select(predicate, orderBy, includeProperties);
      }
  
      public virtual IQueryable&lt;T&gt; SelectAsQuery(
          Expression&lt;Func&lt;T, bool&gt;&gt; predicate = null,
          Expression&lt;Func&lt;T, string&gt;&gt; orderBy = null,
          string includeProperties = "")
      {
          return this.Repository.SelectAsQuery(predicate, orderBy, includeProperties);
      }
  
      public virtual T Create(T obj)
      {
          return this.Repository.Create(obj);
      }
  
      public virtual T Update(T obj)
      {
          return this.Repository.Update(obj);
      }
  
      public virtual bool Delete(T obj)
      {
          return this.Repository.Delete(obj);
      }
  
      public virtual bool Delete(int id)
      {
          return this.Repository.Delete(id);
      }
  
      public virtual bool Delete(Expression&lt;Func&lt;T, bool&gt;&gt; predicate)
      {
          return this.Repository.Delete(predicate);
      }
  
      public virtual void Dispose()
      {
          if (this.Repository != null)
              this.Repository.Dispose();
      }
  }
  </code></pre>
  
  <p>This works well.</p>
  
  <p>But, we now need to use the same DB table for multiple entity type :</p>
  
  <pre><code>public abstract class AbstractSite : PrivateObject, IActivable, ILogicallyDeletable
  {
      public int Id { get; set; }
  }
  
  public class EthicCommittee : AbstractSite
  {
      public int Number { get; set; }
  }
  
  public class Site : AbstractSite
  {
      public string Name { get; set; }
  }
  </code></pre>
  
  <p>This is how we use the generic managers : </p>
  
  <pre><code>public class AbstractSiteManager : BaseManager&lt;AbstractSite&gt;
  {
      public AbstractSiteManager (PrismaDAL prismaDAL = null)
      {
          this.Repository = new AbstractSiteRep(prismaDAL);
      }
  }
  </code></pre>
  
  <p>and how we use the generic repositories :</p>
  
  <pre><code>public class AbstractSiteRep : PrismaBaseRep&lt;AbstractSite&gt;
  {
      public AbstractSiteRep (PrismaDAL prismaDAL = null)
          : base(prismaDAL)
      {}
  }
  
  public class PrismaBaseRep&lt;T&gt; : BaseRep&lt;T&gt; where T : class, PrivateObject
  {
      public PrismaBaseRep(PrismaDAL prismaDAL = null) : base((prismaDAL == null) ? new PrismaDAL() : prismaDAL)
      { }
  }
  </code></pre>
  
  <p>But now, we would like to use the concrete types and not the abstract type anymore (AbstractSite = abstract; Site = concrete, RecruitingInstitution = concrete...) without touching the generic repository / manager. So we would have X generic repository (where X : number of concrete types). All of them pointing to the same DB table. 
  This would allow us to avoid a cast and allow us to restrict which type we can manipulate using one manager / repository.</p>
  
  <p>Do you, guys, have any idea how i could accomplish this ?</p>