2015-07-16 15 views
6

Sto lavorando a un'applicazione C# MVC utilizzando il modello di repository. Sto usando Unity come mio IoC per implementare il mio repository all'interno dell'applicazione MVC.C# tipi generici e modello di repository

Ho creato il seguente tipo generico con l'obiettivo di ridurre al minimo la replica del codice in tutte le mie applicazioni. Ecco un esempio:

public abstract class GenericRepository<T, C> : IDisposable,IGenericRepository<T> where T : class where C : DbContext, new() 


public async void AddObjectAsync<T>(T entity) where T : class 
    { 
     try 
     { 
      // Validate that that there is not an existing object in the database. 
      var x = _context.Entry(entity); 
      if (!Exists(entity)) 
      { 
       _context.Set<T>().Add(entity); // Add the entry if it does not exist. 
       _context.SaveChanges(); 
      } 
      else 
      { 
       UpdateObjectAsync(entity); // Update the entry if it did exist. 
      } 
     } 
     catch 
     { 
      throw; 
     } 

Questo sta lavorando molto quando uso una strategia TPC o TPH, tuttavia non gioca bene con una strategia TPT. Un esempio:

public abstract class Component 
{ 
    [Key] 
    public Guid ComponentId { get; set; } 

    public string Manufacturer { get; set; } 
} 
public class SpecialComponent : Component 
{ 
    public string ExtraSpecialProperty { get; set; } 
} 

mia implementazione all'interno del ComponentRepository:

public class ComponentRepository : GenericRepository<Component, HappyDbContext>, IComponentRepository 
{ 
public async void AddComponentAsync<T>(T component) where T : class 
    { 
     try 
     { 

      if(component != null) 
      { 
       AddObjectAsync(component); 
      } 
      else 
      { 
      throw new ArgumentNullException(); 
      } 

     } 
     catch (ArgumentNullException ex) 
     { 
      _logger.WriteErrorLogAsync(ex); 
      throw ex; 
     } 
    } 

La prima riga di questo blocco di codice è quello che sto avendo difficoltà con. Per inizializzare il tipo GenericRepository ho bisogno di inserire una classe per T. In questo caso il DbContext C sarà sempre lo stesso, quindi non è preoccupante.

Come posso implementare un modello completamente generico che funzioni con tipi ereditati? Se si trattasse di un numero limitato di elementi, sarei meno preoccupato, tuttavia non è il caso in questa situazione. Penso che ci sia sicuramente un modo migliore per gestirlo, quindi ti sto contattando per il tuo contributo.

+0

Qual è il rapporto tra il parametro 'T' sulla Classe GenericRepository e il parametro 'T' su AddObjectAsync? – StriplingWarrior

+1

Questa è una situazione in cui è possibile utilizzare la composizione sull'ereditarietà? Se ComponentRepository ha iniettato una factory specializzata in grado di costruire istanze di GenericRepository, quindi 'AddComponentAsync' potrebbe chiamare in quella factory per costruire un repository tipicamente generico basato sul tipo fornito per quel metodo. – StriplingWarrior

+0

Spiacente, ho letto male il tuo commento. Loro sono la stessa cosa. Se passiamo l'Entità "Componente" AddObjectAsync sarà del tipo e aspettiamo un parametro metodo di (Entità componente). –

risposta

0

Sembra che si potrebbe avere un caso di essere "over-generico".

Fare il DbContext generico sembra una perdita di tempo se è codificato in 2 posizioni. Ad esempio GenericRepository<Component, HappyDbContext> e where C : DbContext, new(). La forte digitazione del campo _context e l'iniezione di HappyDbContext utilizzando Unity dal potente repository digitato potrebbe avere più senso.

spostando anche l'entità generica digitare fino al livello di metodo, piuttosto che la classe potrebbe semplificare le cose così:

public interface IGenericRepository 
{ 
    void AddObjectAsync<T>(T entity) where T : class; 
} 

public class GenericRepository : IGenericRepository 
{ 
    private readonly DbContext _context; 

    public GenericRepository(DbContext context) 
    { 
     _context = context; 
    } 

    .... 

    public async void AddObjectAsync<T>(T entity) where T : class 
    { 
     // Validate that that there is not an existing object in the database. 
     var x = _context.Entry(entity); 
     if (!Exists(entity)) 
     { 
      _context.Set<T>().Add(entity); // Add the entry if it does not exist. 
      _context.SaveChanges(); 
     } 
     else 
     { 
      UpdateObjectAsync(entity); // Update the entry if it did exist. 
     } 
    } 
} 

public interface IComponentRepository 
{ 
    void AddComponentAsync(Component component); 
    // or void AddComponentAsync<T>(T component); 
    // depends if you'll be reusing the ComponentRepository 
    // for types that inherit Component but still have individual tables... 
    // It was a little difficult to tell from your example. 
} 

public class ComponentRepository : GenericRepository, IComponentRepository 
{ 
    public ComponentRepository(DbContext context) : base(context) { } 

    ... 

    public async void AddComponentAsync(Component component) 
    { 
     try 
     { 
      if (component == null) throw new ArgumentNullException(); 
      AddObjectAsync(component); 
     } 
     catch (ArgumentNullException ex) 
     { 
      _logger.WriteErrorLogAsync(ex); 
      throw ex; 
     } 
    } 
} 

Speriamo che questo aiuta