0

J'ai un modèle de référentiel que j'utilise pour une application. Tout fonctionne parfaitement aujourd'hui. Cependant, je veux ajouter la capacité d'inclure des relations à d'autres modèles.Comment puis-je ajouter une relation à mon modèle de référentiel avec C#?

Voici ma position actuelle IRepository

public interface IRepository<TModel> 
    where TModel : class 
{ 

    // Get records by it's primary key 
    TModel Get(int id); 

    // Get all records 
    IEnumerable<TModel> GetAll(); 

    // Get all records matching a lambda expression 
    IEnumerable<TModel> Find(Expression<Func<TModel, bool>> predicate); 

    // Get the a single matching record or null 
    TModel SingleOrDefault(Expression<Func<TModel, bool>> predicate); 

    // Add single record 
    TModel Add(TModel entity); 

    // Add multiple records 
    IEnumerable<TModel> AddRange(IEnumerable<TModel> entities); 

    // Remove records 
    void Remove(TModel entity); 

    // remove multiple records 
    void RemoveRange(IEnumerable<TModel> entities); 
} 

Voici ma mise en œuvre de l'entité

public class EntityRepository<TEntity> : IRepository<TEntity> 
where TEntity : class 
{ 
protected readonly DbContext Context; 

protected readonly DbSet<TEntity> DbSet; 

public EntityRepository(DbContext context) 
{ 
    Context = context; 
    DbSet = context.Set<TEntity>(); 
} 

public TEntity Get(int id) 
{ 
    return DbSet.Find(id); 
} 

public IEnumerable<TEntity> GetAll() 
{ 
    return DbSet.ToList(); 
} 

public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate) 
{ 
    return DbSet.Where(predicate); 
} 

public TEntity SingleOrDefault(Expression<Func<TEntity, bool>> predicate) 
{ 
    return DbSet.SingleOrDefault(predicate); 
} 

public TEntity Add(TEntity entity) 
{ 
    TEntity record = DbSet.Add(entity); 

    return record; 
} 

public IEnumerable<TEntity> AddRange(IEnumerable<TEntity> entities) 
{ 
    IEnumerable<TEntity> records = DbSet.AddRange(entities); 

    return records; 
} 

public void Remove(TEntity entity) 
{ 
    DbSet.Remove(entity); 
} 

public void RemoveRange(IEnumerable<TEntity> entities) 
{ 
    DbSet.RemoveRange(entities); 
} 

Maintenant, je veux ajouter une autre méthode pour me permettent de gérer le chargement paresseux. En d'autres mots, je veux être en mesure de faire quelque chose comme ça

using(var con = new UnitOfWork()) 
{ 
    var task = con.Tasks.With(x => x.Owner).GetAll(); 
} 

Ici, dans mon unité de classe de travail

public sealed class UnitOfWork : IUnitOfWork 
{ 
    private bool Disposed = false; 
    private readonly ModuleContext Context; 

    public ITaskRepository Tasks { get; private set; } 

    public UnitOfWork(ModuleContext context) 
    { 
     Context = context; 
     Tasks = new TaskRepository(Context); 
    } 

    public int Save() 
    { 
     return Context.SaveChanges(); 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
    } 

    private void Dispose(bool disposing) 
    { 
     if (!Disposed && Context != null && disposing) 
     { 
      Context.Dispose(); 
     } 

     Disposed = true; 
    } 
} 

Voici mon modèle de tâche

public class Task 
{ 
    public string Name { get; set; } 

    [ForeignKey("Client")] 
    public int ClientId { get; set; } 

    [ForeignKey("Owner")] 
    public int? OwnerId { get; set; } 

    public virtual Client Client { get; set; } 
    public virtual User Owner { get; set; } 
} 

Comment J'ajoute un moyen de me permettre d'inclure des relations à différents modèles?

+0

Vider le dépôt/l'unité de travail. Voir: https://cpratt.co/repository-and-unit-of-work-patterns-with-entity-framework/. TL; DR: Entity Framework * déjà * implémente ces modèles. Votre 'DbContext' est votre unité de travail et chaque' DbSet' est un référentiel. Tout ce que vous faites est d'ajouter une autre abstraction sans signification, qui nécessite une maintenance supplémentaire. –

+1

S'il est vrai que DbContext les implémente déjà, nous ne connaissons pas les intentions de l'OP. Il se peut qu'ils souhaitent éliminer complètement EF pour que le DAL puisse ensuite s'appuyer sur une autre technologie (peut-être EF core). Dans ce cas, cela ne fait pas de différence si DbContext implémente déjà ces modèles. Aussi, se moquer de votre DAL si vous avez une couche de référentiel/unité de travail peut être plus facile pour les tests unitaires. Dans mon expérience, se moquer du DbContext est un peu compliqué. –

+1

Et si je ne veux pas utiliser EF plus tard? Et ... Si je vider le motif selon votre suggestion. Où devrais-je enregistrer mon code réutilisable? Si j'ai une clause where que j'utilise partout, où devrais-je la sauvegarder, alors j'ai une place pour toute ma logique –

Répondre

0

Ajoutez une surcharge pour vos méthodes à l'interface du référentiel afin d'accepter une liste d'expressions include possibles. Par exemple.

public IEnumerable<TEntity> FindAll(params Expression<Func<TEntity,object>> includes) 
{ 
    var query = DbSet; 
    foreach (var include in includes) 
    { 
     query = query.Include(include); 
    } 
    return query.ToList(); 
} 

Et vous pouvez simplement écrire:

uow.Tasks.GetAll(t=>t.Owner); 

Pour le cas filtré, vous pouvez faire quelque chose comme ceci:

public IEnumerable<TEntity> Find(Expression<Func<TEntity,bool>> filter, params Expression<Func<TEntity,object>> includes) 
{ 
    var query = DbSet; 
    foreach (var include in includes) 
    { 
     query = query.Include(include); 
    } 
    return query.Where(filter).ToList(); 
} 

Et vous pouvez simplement écrire:

uow.Tasks.Find(t=>t.Something==2, t=>t.Owner); 
+0

Merci. Qu'en est-il dans le cas où je veux filtrer puis inclure des relations? .where(). include() ... –

+0

Voir mon exemple mis à jour pour le cas filtré. –

+0

Merci pour la mise à jour. Mais, quel est le problème avec le retour «IQueryable »? –