C#实体框架:使用自定义IQueryable实现枚举实体的问题
我使用.NETFramework4.8和EntityFramework6.2 我有一个C#实体框架:使用自定义IQueryable实现枚举实体的问题,c#,entity-framework,linq,iqueryable,C#,Entity Framework,Linq,Iqueryable,我使用.NETFramework4.8和EntityFramework6.2 我有一个IOrderedQueryable实现: public sealed class EFQueryable<T> : IOrderedQueryable<T>, IDbAsyncEnumerable<T> { private static readonly Type _type = typeof(T); private readonly IEFQueryProv
IOrderedQueryable
实现:
public sealed class EFQueryable<T> : IOrderedQueryable<T>, IDbAsyncEnumerable<T>
{
private static readonly Type _type = typeof(T);
private readonly IEFQueryProvider _provider;
public Type ElementType => _type;
public Expression Expression { get; }
public IQueryProvider Provider => _provider;
public EFQueryable(IEFQueryProvider queryProvider)
{
_provider = queryProvider;
Expression = Expression.Constant(this);
}
public EFQueryable(IEFQueryProvider queryProvider, Expression expression)
{
_provider = queryProvider;
Expression = expression;
}
public IEnumerator<T> GetEnumerator() => _provider.GetEnumerator<T>(Expression);
IEnumerator IEnumerable.GetEnumerator() => _provider.GetEnumerator(Expression);
}
public class EFQueryProvider<TEntity> : IEFQueryProvider where TEntity : class
{
private readonly IDbContextFactory _dbContextFactory;
public EFQueryProvider(IDbContextFactory dbContextFactory)
{
_dbContextFactory = dbContextFactory;
}
public IQueryable CreateQuery(Expression expression)
{
Type elementType = null;
try
{
elementType = expression.Type.GetGenericArguments().First();
return (IQueryable)Activator.CreateInstance(typeof(EFQueryable<>).MakeGenericType(elementType),
BindingFlags.Instance | BindingFlags.NonPublic,
null,
new object[] { this, expression },
null,
null);
}
catch (Exception ex)
{
throw new Exception($"Unable to create instance of 'RsQueryable<{(elementType ?? expression.Type).Name}>'. {ex.Message}", ex);
}
}
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
try
{
return new EFQueryable<TElement>(this, expression);
}
catch (Exception ex)
{
throw new Exception($"Unable to create instance of '{typeof(EFQueryable<TElement>).Name}'. {ex.Message}", ex);
}
}
public object Execute(Expression expression)
{
try
{
using (var db = _dbContextFactory.CreateDbContext())
{
var queryable = db.Set<TEntity>().AsNoTracking();
var convertedExpression = ChangeQueryableInExpression(expression, queryable);
return queryable.Provider.Execute(convertedExpression);
}
}
catch (Exception ex)
{
throw new Exception($"Unable to query repository. {ex.Message}", ex);
}
}
public TResult Execute<TResult>(Expression expression)
{
try
{
using (var db = _dbContextFactory.CreateDbContext())
{
var queryable = db.Set<TEntity>().AsNoTracking();
var convertedExpression = ChangeQueryableInExpression(expression, queryable);
return queryable.Provider.Execute<TResult>(convertedExpression);
}
}
catch (Exception ex)
{
throw new Exception($"Unable to query repository. {ex.Message}", ex);
}
}
public Task<object> ExecuteAsync(Expression expression, CancellationToken cancellationToken)
{
return Task.Run(() => Execute(expression), cancellationToken);
}
public Task<TResult> ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken)
{
return Task.Run(() => Execute<TResult>(expression), cancellationToken);
}
public IEnumerator<T> GetEnumerator<T>(Expression expression)
{
try
{
using (var db = _dbContextFactory.CreateDbContext())
{
var queryable = db.Set<TEntity>().AsNoTracking();
var convertedExpression = ChangeQueryableInExpression(expression, queryable);
return queryable.Provider.Execute<IEnumerable<T>>(convertedExpression).ToList().GetEnumerator();
}
}
catch (Exception ex)
{
throw new Exception($"Unable to query repository. {ex.Message}", ex);
}
}
public IEnumerator GetEnumerator(Expression expression)
{
try
{
using (var db = _dbContextFactory.CreateDbContext())
{
var queryable = db.Set<TEntity>().AsNoTracking();
var convertedExpression = ChangeQueryableInExpression(expression, queryable);
return queryable.Provider.Execute<IEnumerable>(convertedExpression).Cast<object>().ToList().GetEnumerator();
}
}
catch (Exception ex)
{
throw new Exception($"Unable to query repository. {ex.Message}", ex);
}
}
private static Expression ChangeQueryableInExpression(Expression expression, IQueryable<TEntity> queryable)
{
var visitor = new ExpressionQueryableSourceModifier(queryable.Expression);
return visitor.Visit(expression);
}
private sealed class ExpressionQueryableSourceModifier : ExpressionVisitor
{
private readonly Expression _expression;
private static readonly Type _queryableTypeToReplace = typeof(EFQueryable<TEntity>);
public ExpressionQueryableSourceModifier(Expression expression)
{
_expression = expression;
}
protected override Expression VisitConstant(ConstantExpression node)
{
return node.Type == _queryableTypeToReplace ? _expression : base.VisitConstant(node);
}
}
}
及其实施:
public sealed class EFQueryable<T> : IOrderedQueryable<T>, IDbAsyncEnumerable<T>
{
private static readonly Type _type = typeof(T);
private readonly IEFQueryProvider _provider;
public Type ElementType => _type;
public Expression Expression { get; }
public IQueryProvider Provider => _provider;
public EFQueryable(IEFQueryProvider queryProvider)
{
_provider = queryProvider;
Expression = Expression.Constant(this);
}
public EFQueryable(IEFQueryProvider queryProvider, Expression expression)
{
_provider = queryProvider;
Expression = expression;
}
public IEnumerator<T> GetEnumerator() => _provider.GetEnumerator<T>(Expression);
IEnumerator IEnumerable.GetEnumerator() => _provider.GetEnumerator(Expression);
}
public class EFQueryProvider<TEntity> : IEFQueryProvider where TEntity : class
{
private readonly IDbContextFactory _dbContextFactory;
public EFQueryProvider(IDbContextFactory dbContextFactory)
{
_dbContextFactory = dbContextFactory;
}
public IQueryable CreateQuery(Expression expression)
{
Type elementType = null;
try
{
elementType = expression.Type.GetGenericArguments().First();
return (IQueryable)Activator.CreateInstance(typeof(EFQueryable<>).MakeGenericType(elementType),
BindingFlags.Instance | BindingFlags.NonPublic,
null,
new object[] { this, expression },
null,
null);
}
catch (Exception ex)
{
throw new Exception($"Unable to create instance of 'RsQueryable<{(elementType ?? expression.Type).Name}>'. {ex.Message}", ex);
}
}
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
try
{
return new EFQueryable<TElement>(this, expression);
}
catch (Exception ex)
{
throw new Exception($"Unable to create instance of '{typeof(EFQueryable<TElement>).Name}'. {ex.Message}", ex);
}
}
public object Execute(Expression expression)
{
try
{
using (var db = _dbContextFactory.CreateDbContext())
{
var queryable = db.Set<TEntity>().AsNoTracking();
var convertedExpression = ChangeQueryableInExpression(expression, queryable);
return queryable.Provider.Execute(convertedExpression);
}
}
catch (Exception ex)
{
throw new Exception($"Unable to query repository. {ex.Message}", ex);
}
}
public TResult Execute<TResult>(Expression expression)
{
try
{
using (var db = _dbContextFactory.CreateDbContext())
{
var queryable = db.Set<TEntity>().AsNoTracking();
var convertedExpression = ChangeQueryableInExpression(expression, queryable);
return queryable.Provider.Execute<TResult>(convertedExpression);
}
}
catch (Exception ex)
{
throw new Exception($"Unable to query repository. {ex.Message}", ex);
}
}
public Task<object> ExecuteAsync(Expression expression, CancellationToken cancellationToken)
{
return Task.Run(() => Execute(expression), cancellationToken);
}
public Task<TResult> ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken)
{
return Task.Run(() => Execute<TResult>(expression), cancellationToken);
}
public IEnumerator<T> GetEnumerator<T>(Expression expression)
{
try
{
using (var db = _dbContextFactory.CreateDbContext())
{
var queryable = db.Set<TEntity>().AsNoTracking();
var convertedExpression = ChangeQueryableInExpression(expression, queryable);
return queryable.Provider.Execute<IEnumerable<T>>(convertedExpression).ToList().GetEnumerator();
}
}
catch (Exception ex)
{
throw new Exception($"Unable to query repository. {ex.Message}", ex);
}
}
public IEnumerator GetEnumerator(Expression expression)
{
try
{
using (var db = _dbContextFactory.CreateDbContext())
{
var queryable = db.Set<TEntity>().AsNoTracking();
var convertedExpression = ChangeQueryableInExpression(expression, queryable);
return queryable.Provider.Execute<IEnumerable>(convertedExpression).Cast<object>().ToList().GetEnumerator();
}
}
catch (Exception ex)
{
throw new Exception($"Unable to query repository. {ex.Message}", ex);
}
}
private static Expression ChangeQueryableInExpression(Expression expression, IQueryable<TEntity> queryable)
{
var visitor = new ExpressionQueryableSourceModifier(queryable.Expression);
return visitor.Visit(expression);
}
private sealed class ExpressionQueryableSourceModifier : ExpressionVisitor
{
private readonly Expression _expression;
private static readonly Type _queryableTypeToReplace = typeof(EFQueryable<TEntity>);
public ExpressionQueryableSourceModifier(Expression expression)
{
_expression = expression;
}
protected override Expression VisitConstant(ConstantExpression node)
{
return node.Type == _queryableTypeToReplace ? _expression : base.VisitConstant(node);
}
}
}
这是:
public IQueryable<TEntity> AsQueryable(Expression<Func<TEntity, bool>> where)
{
return AsQueryable().Where(where);
}
SingleOrDefaultAsync
工作非常好。但是ToList
甚至ToListAsync
都不需要。我得到以下错误:
从物化的“Entities.Domain.Config”类型到“System.Collections.Generic.IEnumerable`1[Entities.Domain.Config]”类型的指定强制转换无效
你能帮我解决我的问题吗?我真的需要用那种方式使用AsQueryable
我想这可能是我的问题
Expression = Expression.Constant(this);
在EFQueryable
构造函数中。但是我能用这个做什么呢
对于
AsQueryable().Where(expression)
我可以创建自己的扩展方法,但我不能为每个特定的用例创建扩展方法。我非常感谢任何帮助,使我的实施工作有些奇怪。通过这个IQueryable实现,您想要实现什么?问这个问题是因为我知道这方面的几乎所有知识,并且没有看到这一实现探索的好处。@SvyatoslavDanyliv我在桌面上有很多遗留代码,它们使用DbContext作为存储库的构造函数参数。在进行一些小更改时,我需要重新编写通用存储库,因此它将DbContextFactory作为依赖项,而不是DbContext。遗留存储库具有这种奇怪的特性,可以将逻辑暴露在存储库之外。我现在不会写这样的代码,但我不能简单地重写数千行代码。所以我需要让它工作,我在.NET5和EFCore上尝试了相同的实现。它确实有效。所以问题在于我在.NETFramework应用程序中使用的EF6
Expression = Expression.Constant(this);