2014-12-15 15 views
5

Sto provando a creare una libreria con un repository generico per un utilizzo futuro nella mia app MVC. Il codice è il seguente ...Repository generico aggiunge un metodo personalizzato

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(); 
    } 
} 

E questi sono alcuni dei miei corsi 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>(); 
    } 
} 

Il mio problema è che non implementare il metodo ...

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

si tratta di un metodo generico, che deve restituire solo i risultati, quando è di tipo IAuditable ..., deve essere qualcosa di così ...

public virtual IEnumerable<T> GetByUsuarioId(int usuarioId) 
    { 
     return _dbset.FindBy(c => c.UsuarioId == usuarioId); 
    } 

Potete aiutarmi ?, Grazie.

Ciao C Bauer ...

Si noti che ...

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; } 
} 

E il mio GenericRepositry è ..

public interface IGenericRepository<T> where T : BaseEntity 

Poi ora ¿?

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

Stai solo cercando di garantire che il parametro generico 'T' implementi' IAuditable'? Questo è lo scopo dei vincoli generici: http://msdn.microsoft.com/en-us/library/d5x73970.aspx. –

+0

Ad esempio Documento.cs implementa AuditableEntity ... –

+0

@ JesúsSánchez Ciao Gesù, dovresti evitare di modificare altri utenti nelle tue risposte. Invece aggiungi un commento per rispondere che affronta il problema che hai con il loro codice. –

risposta

0

Se questo è qualcosa che sarà sempre vero, aggiungerlo al tuo metodo virtuale di base deve essere eseguita in tutta la base di codice.

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); 
} 

scontato, per i commenti qui sotto (e grazie a tutti voi), ci sono sia problemi di prestazioni e potenziali problemi di logica-nascondigli con questa soluzione. Non è certo il modo più elegante per risolvere il problema, ma in realtà lo risolve.

+0

Vorrei lanciare una NotImplementedException o qualcosa del genere, poiché restituire null è un termine improprio. –

+0

@CBauer Sono completamente d'accordo. Detto questo, il codice dell'OP restituisce null e preferisco non interpretare il suo intento su ciò che vuole restituire. –

+0

C Bauer, ho modificato la mia domanda originale, per favore controlla ... Grazie –

2

è possibile implementare una classe di estensione repository digitato in modo che funzioni solo su IRepository<IAuditable>:

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

Edit:

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(); 
     } 
    } 
} 
+0

Dovrei quindi utilizzare due repository? ... GenericRepository e AuditableRepo ?? –

+0

Beh, questo dipende da come la tua applicazione è stata progettata. Ho sempre usato il repository per standardizzare il modo in cui è costruito l'accesso ai dati. Si può fare altrettanto facilmente: 'var auditableRepoNotUsingTheActualClass = new GenericRepository ();' 'auditableRepoNotUsingTheActualClass.GetUsuarioById (1); // funziona ancora! ' –

+0

@ JesúsSánchez Puoi ancora usare il tuo codice originale, l'esempio che ho postato è solo un piccolo esempio del codice e di come funziona. –

0

Non sono sicuro di come si prevede di usando questi repository nella tua codice (quindi questo potrebbe non funzionare necessariamente con il modo in cui li stai consumando), ma perché non aggiungere un altro livello di ereditarietà?

Nel vostro GenericRepository:

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

quindi creare un repository per i tipi controllabili:

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

in cui si implementano la logica rilevanti:

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

Ovviamente questo significa che il tuo codice di consumo deve conoscere i diversi repository, ma come dico io t dipende da come li stai usando. Se stavi usando IoC potresti iniettare i repository corretti.

Problemi correlati