正如 cmets 中所指出的,没有反射或将每个实体实现为项目中的类型是不可能的。
最后一种方法可能如下所示。当您创建实现IQueryable<T> 的基类时,添加新实体所需的代码很少,并且当有多个DbContext 可用于注入时也可以工作,这几乎总是在任何非简单的演示应用程序。
public abstract class QueryableEntityBase<TEntity> : IQueryable<TEntity> where TEntity : class
{
protected QueryableEntityBase(DbContext context)
{
Context = context ?? throw new ArgumentNullException(nameof(context));
Queryable = context.Set<TEntity>().AsQueryable();
}
public Type ElementType => Queryable.ElementType;
public Expression Expression => Queryable.Expression;
public IQueryProvider Provider => Queryable.Provider;
protected IQueryable<TEntity> Queryable { get; }
private DbContext Context { get; }
public IEnumerator<TEntity> GetEnumerator() => Queryable.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => Queryable.GetEnumerator();
}
// You need to create this per entity you want to be injectable
public class MyQueryableEntity : QueryableEntityBase<MyEntity>
{
public MyQueryableEntity(ApplicationDbContext context) : base(context) { }
}
这具有额外的优势,您可以通过将QueryableEntityBase<T> 基础更改为使用IMongoClient 而不是DbContext 的MonogoDbQueryableEntityBase<T>,来按实体更改基础查询/持久性提供程序。
注册应该是这样的(不熟悉 StructureMap,你需要注册它的所有类型或者扫描程序集)。
config.For(typeof(IQueryable<>)).Use(typeof(QueryableEntityBase<>));
在您只有一个数据库的简单情况下,您还可以使基类成为非抽象类并仅解析 QueryableEntity<T>,但就像我说的那样,您很快就会遇到每个应用程序一个 DbContext 的限制,或者稍后,所以最好明确地完成。
或者扩展实现,以便您也可以定义上下文
public class QueryableEntityBase<TContext, TEntity> : IContextSetQueryable<TDbContext, TEntity>, IQueryable<TEntity> where TEntity : class, TContext : DbContext
{
private TContext Context { get; }
protected QueryableEntityBase(TContext context)
{
Context = context ?? throw new ArgumentNullException(nameof(context));
Queryable = context.Set<TEntity>().AsQueryable();
}
}
但是你需要一个额外的接口:
public interface IContextSetQueryable<TContext, TContext> : IQueryable<TEntity> where TContext : DbContext { }
然后将IContextSetQueryable<TContext, TContext> entity 注入您的服务。
但是你失去了拥有持久性无关域的能力,因为你需要能够引用 DbContext 及其子类型,所以它不是很优雅,你也可以使用数据库特定的接口,例如
public interface ISomethingDatabase
{
IQueryable<User> Users { get; }
IQueryable<Customer> Customers { get; }
...
}