通用存储库添加自定义方法

时间:2014-12-15 18:47:32

标签: c# asp.net-mvc generics

我正在尝试使用Generic Repository创建一个库,以便以后在我的MVC App中使用。代码如下......

public abstract class BaseEntity
{
}

public interface IEntity<T>
{
    T Id { get; set; }
}

public abstract class Entity<T> : BaseEntity, IEntity<T>
{
    public virtual T Id { get; set; }
}

public interface IAuditableEntity
{
    int? UsuarioId { get; set; }
    DateTime CreatedDate { get; set; }
    string CreatedBy { get; set; }
    DateTime UpdatedDate { get; set; }
    string UpdatedBy { get; set; }
}

public abstract class AuditableEntity<T> : Entity<T>, IAuditableEntity
{
    public int? UsuarioId { get; set; }
    public DateTime CreatedDate { get; set; }
    public string CreatedBy { get; set; }
    public DateTime UpdatedDate { get; set; }
    public string UpdatedBy { get; set; }
}   

public interface IGenericRepository<T> where T : BaseEntity
{
    IEnumerable<T> GetAll();
    IEnumerable<T> GetByUsuarioId(int usuarioId);
    T GetById(int id);
    T Add(T entity);
    T Delete(T entity);
    void Edit(T entity);
    void Save();
}

public class GenericRepository<T> : IGenericRepository<T>
   where T : BaseEntity
{
    protected DbContext _entities;
    protected readonly IDbSet<T> _dbset;

    public GenericRepository(DbContext context)
    {
        _entities = context;
        _dbset = context.Set<T>();
    }

    public virtual IEnumerable<T> GetAll()
    {
        return _dbset.AsEnumerable<T>();
    }

    public IEnumerable<T> FindBy(Expression<Func<T, bool>> predicate)
    {
        IEnumerable<T> query = _dbset.Where(predicate).AsEnumerable();
        return query;
    }


    public virtual IEnumerable<T> GetByUsuarioId(int usuarioId)
    {
        // NO SÉ COMO IMPLEMENTAR ESTE METODO!!!!!
        return null;
        // NO SÉ COMO IMPLEMENTAR ESTE METODO!!!!!
    }

    public virtual T GetById(int id)
    {
        return _dbset.Find(id);
    }

    public virtual T Add(T entity)
    {
        return _dbset.Add(entity);
    }

    public virtual T Delete(T entity)
    {
        return _dbset.Remove(entity);
    }

    public virtual void Edit(T entity)
    {
        _entities.Entry(entity).State = EntityState.Modified;
    }

    public virtual void Save()
    {
        _entities.SaveChanges();
    }
}

这些是我的一些课程POCO ......

   public class Documento : AuditableEntity<int>
{
    public string Descripcion { get; set; }        
    public string Foto { get; set; }

    public virtual Usuario Usuario { get; set; }
}

public class Gasto : AuditableEntity<int>
{
    public int? TaxiId { get; set; }        
    public int TipoGastoId { get; set; }
    public DateTime Fecha { get; set; }
    public double Importe { get; set; }
    public int Kilometros { get; set; }
    public string Descripcion { get; set; }
    public string Foto { get; set; }

    public virtual Usuario Usuario { get; set; }
    public virtual Taxi Taxi { get; set; }
    public virtual TipoGasto TipoGasto { get; set; }
    public virtual PartidaTarjetas PartidaTarjetas { get; set; }

    public virtual ICollection<Tarea> Tareas { get; set; }      

    public int? PartidaTarjetasId { get; set; }

    public Gasto()
    {
        Tareas = new List<Tarea>();
    }
}   

public class Nivel : Entity<int>
{
    public string Descripcion { get; set; }
    public string PaginaInicio { get; set; }

    public virtual ICollection<Usuario> Usuarios { get; set; }

    public Nivel()
    {
        Usuarios = new List<Usuario>();
    }
}   

我的问题是它不会实现方法......

    public virtual IEnumerable<T> GetByUsuarioId(int usuarioId)
    {
        // NO SÉ COMO IMPLEMENTAR ESTE METODO!!!!!
        return null;
      // NO SÉ COMO IMPLEMENTAR ESTE METODO!!!!!
    }

这是一种通用方法,只有在IAuditable类型时才返回结果...,必须是某些东西......

    public virtual IEnumerable<T> GetByUsuarioId(int usuarioId)
    {
        return _dbset.FindBy(c => c.UsuarioId == usuarioId);
    }
你帮我吗? 感谢。

Hello C Bauer ......

请注意......

public abstract class BaseEntity
{
}

public interface IEntity<T>
{
    T Id { get; set; }
}

public abstract class Entity<T> : BaseEntity, IEntity<T>
{
    public virtual T Id { get; set; }
}

public interface IAuditableEntity
{
    int? UsuarioId { get; set; }
    DateTime CreatedDate { get; set; }
    string CreatedBy { get; set; }
    DateTime UpdatedDate { get; set; }
    string UpdatedBy { get; set; }
}

public abstract class AuditableEntity<T> : Entity<T>, IAuditableEntity
{
    public int? UsuarioId { get; set; }
    public DateTime CreatedDate { get; set; }
    public string CreatedBy { get; set; }
    public DateTime UpdatedDate { get; set; }
    public string UpdatedBy { get; set; }
}   

我的GenericRepositry是..

public interface IGenericRepository<T> where T : BaseEntity

然后现在¿?

public interface IGenericRepository<T> where T : ¿¿ ??

3 个答案:

答案 0 :(得分:2)

您可以实现类型化存储库扩展类,以便它仅适用于IRepository<IAuditable>

    public static class Extensions
    {
        public static IEnumerable<IAuditable> GetUsuarioById(this IRepository<IAuditable> repository, int id)
        {
            return repository.FindBy(audible => audible.Id == id);
        }
    }

编辑:

using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace StackOverflowPlayground
{
    class JesusPlayground
    {
        public JesusPlayground()
        {
            var auditableRepo = new AuditableRepo();
            auditableRepo.GetUsuarioById(1);

            var otherRepo = new OtherRepo();
            //otherRepo. (does not have GetUsuarioById


            var auditableRepoNotUsingTheActualClass = new GenericRepository<IAuditable>();
            auditableRepoNotUsingTheActualClass.GetUsuarioById(1); //still works!
        }
    }


    public static class Extensions
    {
        public static IEnumerable<IAuditable> GetUsuarioById(this IRepository<IAuditable> repository, int id)
        {
            return repository.FindBy(audible => audible.Id == id);
        }
    }



    public class OtherRepo : IRepository<OtherType>
    {
        public IEnumerable<OtherType> FindBy(Expression<Func<OtherType, bool>> expr)
        {
            throw new NotImplementedException();
        }
    }

    public class OtherType
    {
    }

    public interface IAuditable
    {
        int Id { get; set; }
    }

    public interface IRepository<T>
    {
        IEnumerable<T> FindBy(Expression<Func<T, bool>> expr);
    }

    public class GenericRepository<T> : IRepository<T>
    {
        public IEnumerable<T> FindBy(Expression<Func<T, bool>> expr)
        {
            throw new NotImplementedException();
        }
    }
    class AuditableRepo : IRepository<IAuditable>
    {
        public IEnumerable<IAuditable> FindBy(Expression<Func<IAuditable, bool>> expr)
        {
            throw new NotImplementedException();
        }
    }
}

答案 1 :(得分:0)

如果这始终是真的,请将其添加到您的基本虚拟方法中,以便在整个代码库中强制执行。

public virtual IEnumerable<T> GetByUsuarioId(int usuarioId)
{
    if (!typeof(T).GetInterfaces().Contains(typeof(IAuditable))
        return Enumerable.Empty<T>(); // per OffHeGoes' suggestion

    return _dbset.FindBy(c => c.UsuarioId == usuarioId);
}

当然,根据以下评论(并且谢谢大家),这个解决方案存在性能问题和潜在的逻辑隐藏问题。它不是解决问题的最优雅方式,但确实解决了这个问题。

答案 2 :(得分:0)

不确定您是如何计划在代码中使用这些存储库的(因此这可能不一定与您如何使用它们有关),但为什么不添加另一层继承?

在GenericRepository中:

public virtual IEnumerable<T> GetByUsuarioId(int usuarioId)
{
    //TODO: default behaviour
}

然后为Auditable类型创建一个存储库:

public class AuditableRepository<T> : GenericRepository<T>
    where T: IAuditableEntity, BaseEntity

您实施相关逻辑:

public override IEnumerable<T> GetByUsuarioId(int usuarioId)
{
    //TODO: auditable behaviour
}

显然,这确实意味着你消费代码必须知道不同的存储库,但正如我所说,这取决于你如何使用它们。如果你使用的是IoC,你可以注入正确的存储库。