c#按实体类型获取存储库

时间:2017-09-07 11:41:13

标签: c# generics

我使用Repository模式设计了一些应用程序。我有一个通用的存储库:

public interface IGenericRepository<T> where T : class { // ... }

public class GenericRepository <T> : IGenericRepository<T> where T : class {// ... }

例如,我有两个实体:Order和OrderLine。 对于实体&#34; Order&#34;我只需要通用的存储库方法,所以没关系。 但对于实体&#34; OrderLine&#34;我需要一些通用的存储库方法和一些附加功能。因此,我创建了一个自定义存储库,它扩展了泛型:

    public interface IOrderLinesRepository : IGenericRepository<OrderLine> {...}
    public class OrderLinesRepository : GenericRepository<OrderLine>, IOrderLinesRepository 
    {
      //... this is my additional methods here
    }

但现在我想创建方法,它将按实体类型返回存储库。 如果实体具有自定义存储库 - 应该重新调整它。如果没有,方法必须返回GenericRepository。以下是我尝试创建此内容。

public sealed class RepositoryFactory
{

    // Here is custom repository types
    private IDictionary<Type, Func<DbContext, object>> GetCustomFactories()
    {
        return new Dictionary<Type, Func<DbContext, object>>
        {
            { typeof(OrderLine), dbContext => 
                  new OrderLinesRepository(dbContext) },
        };
    }

    // Custom repository types
    private IDictionary<Type, Type> GetRepositoryTypes()
    {
        return new Dictionary<Type, Type>
        {
            { typeof(OrderLine), typeof(IOrderLinesRepository) }
        };
    }

    private Func<GoodWillDbContext, object> GetDefaultFactory<T>() 
       where T : class
    {
        return dbContext => new GenericRepository<T>(dbContext);
    }

    private Func<DbContext, object> GetFactory<T>() where T : class
    {
        Func<DbContext, object> factory;
        var factories = GetCustomFactories();
        factories.TryGetValue(typeof(T), out factory);
        return factory ?? (factory = GetDefaultFactory<T>());
    }



    public Type GetRepoType(Type type)
    {
        var types = GetRepositoryTypes();
        Type repoType;
        types.TryGetValue(type, out repoType);
        return repoType;
    }

   public object MakeRepository<U>(DbContext dbContext) where U : class
    {
        // Get repository type 
        // If custom type not found, it should be standart type
        // IGenericRepository<U>
        var type = _repositoryFactory.GetRepoType(typeof(U)) ??
         typeof(IGenericRepository<U>);
        var f = _repositoryFactory.GetFactory<U>();
        var repo = f(dbContext);
        return repo;
    }
}

但由于某种原因,它无法正常工作。我有一些问题: 1. MakeRepository应该有什么类型的返回值? 2.我应该如何转换var repo = f(dbContext);到存储库类型?

或许还有另一种方法可以做我需要的事情?

2 个答案:

答案 0 :(得分:0)

对于应该简单的事情,你的代码看起来真的很复杂......下面的例子只是虚拟代码,随时可以根据你的需要进行调整。

public static class RepositoryFactory
{
    public static IGenericRepository<T> MakeRepository<T>(DbContext context) 
        where T : class
    {
        var type = typeof(T);

        if (type == typeof(Car))
        {
            return CarRepositoryFactory.CreateCarRpository(context);
        }
        else if (type == typeof(Boat))
        {
            return BoatRepositoryFactory.CreateBoatRepository(context);
        }
    }
}

如何使用它:

var myRepo = (CarRepository)RepositoryFactory.MakeRepository(new MyContext());

这些代码并不是经常被修改的(你不会在每次提交时都添加一个存储库,对吗?;)),所以请自己帮忙并保持简单。 :)

编辑:如果您真的想保留您的代码,请在我的回复中添加评论,我希望我能做到。 :)

答案 1 :(得分:0)

因此,如果我理解正确,您希望能够通过实体类型获取存储库类型。我稍微修改了你的实现,我认为它应该可以工作。

public sealed class RepositoryFactory
{
    public static RepositoryFactory Instance = new RepositoryFactory();

    // Here is custom repository types
    private IDictionary<Type, Func<DbContext, object>> GetCustomFactories()
    {
        return new Dictionary<Type, Func<DbContext, object>>
        {
            // { typeof(IOrderLinesRepository), dbContext => new OrderLinesRepository(dbContext) },
        };
    }

    // Custom repository types
    private IDictionary<Type, Type> GetRepositoryTypes()
    {
        return new Dictionary<Type, Type>
        {
            { typeof(OrderLine), typeof(IOrderLinesRepository) }
        };
    }

    private Func<DbContext, object> GetDefaultFactory<T>()
        where T : class
    {
        return dbContext => new GenericRepository<T>(dbContext);
    }
    private Func<DbContext, object> GetFactory(Type factoryType)
    {
        if (factoryType == null) return null;
        Func<DbContext, object> factory;
        var factories = GetCustomFactories();
        factories.TryGetValue(factoryType, out factory);
        return factory;
    }
    public Type GetRepoType(Type type)
    {
        var types = GetRepositoryTypes();
        Type repoType;
        types.TryGetValue(type, out repoType);
        return repoType;
    }
    public IGenericRepository<TEntity> MakeRepositoryByEntity<TEntity>(DbContext dbContext) where TEntity : class
    {
        var type = this.GetRepoType(typeof(TEntity));
        var f = this.GetFactory(type) ?? GetDefaultFactory<TEntity>();

        var repo = f(dbContext);
        return (IGenericRepository<TEntity>)repo;
    }

    public TRepo MakeRepository<TRepo, TEntity>(DbContext dbContext)
        where TRepo : class, IGenericRepository<TEntity>
        where TEntity : class
    {
        var repo = this.MakeRepositoryByEntity<TEntity>(dbContext);
        try
        {
            return (TRepo)repo;
        }
        catch (InvalidCastException)
        {
            throw new Exception($"Registered repository for entity ${typeof(TEntity).FullName} does not implement {typeof(TRepo).FullName}");
        }
    }

}

您可以通过以下两种方式之一调用它:

var d = RepositoryFactory.Instance.MakeRepositoryByEntity<OrderLine>(dbContext);
var d2 = RepositoryFactory.Instance.MakeRepository<IOrderLinesRepository, OrderLine>(dbContext);