gpt4 book ai didi

linq - 拦截所有 EF6 Linq 查询

转载 作者:行者123 更新时间:2023-12-04 11:52:38 24 4
gpt4 key购买 nike

我有一个函数,我想在 DbContext 上的每个执行的 Linq 查询上运行该函数,以在执行前修改表达式树。我一直在查看 IDbCommandTreeInterceptor 接口(interface),但它似乎没有提供表达式树(我认为这是可以理解的,因为到现在它可能还不是 Linq 查询)。

有什么方法可以在执行前拦截和修改所有表达式?

注意。这必须是 Linq 树修改,因为我已经构建了一个用于修改 Linq 树的框架,该框架最初用于 Linq to SQL。

最佳答案

为 LINQ 提供程序创建一个代理以拦截每个 LINQ 表达式执行(如评论中所建议)仍然是一个很好的解决方案。事实上,我正在玩弄这些东西within this project ,它明确支持 EF6,包括 EF6 异步查询。您可以创建一个标准的 .NET ExpressionVisitor进行拦截:

intercepted = query.Rewrite(new MyInterceptor());

但问题还要求“在 DbContext 上的每个执行的 Linq 查询上运行”,这将是棘手的部分。一种方法可以是 DbContext 的某种抽象。/ DbSet ,因此您的代码不会直接访问 DbSet对象。在这个抽象的实现内部,可能会发生拦截......

另一种方法(我认为最能回答这个问题)将是 DbSet 的代理。 ,它调用 LINQ 代理进行查询,从而启用拦截。首先,我们必须继承 DbSet :
public class DbSetProxy<TEntity> : DbSet<TEntity>,
IQueryable<TEntity>,
IDbAsyncEnumerable<TEntity>
where TEntity : class
{
private readonly DbSet<TEntity> set;
private readonly DbQuery<TEntity> query;

private readonly IQueryable<TEntity> intercepted;

public DbSetProxy(DbSet<TEntity> set)
: this(set, set)
{
}

public DbSetProxy(DbSet<TEntity> set, DbQuery<TEntity> query)
{
this.set = set;
this.query = query;

// use NeinLinq or any other LINQ proxy library
intercepted = query.Rewrite(new MyInterceptor());
}
}

然后,需要覆盖所有成员才能调用实际的 DbSet。对于非查询的东西:

( 注意 :很遗憾,有必要覆盖每个 DbSet 成员,因为继承 DbSet 仅用于测试 stub 。因此,仅继承 DbSet 会破坏 DbSet 。)
public override DbQuery<TEntity> AsNoTracking()
{
return new DbSetProxy<TEntity>(set, query.AsNoTracking());
}

public override DbQuery<TEntity> AsStreaming()
{
return new DbSetProxy<TEntity>(set, query.AsStreaming());
}

public override DbQuery<TEntity> Include(string path)
{
return new DbSetProxy<TEntity>(set, query.Include(path));
}

public override TEntity Add(TEntity entity)
{
return set.Add(entity);
}

public override IEnumerable<TEntity> AddRange(IEnumerable<TEntity> entities)
{
return set.AddRange(entities);
}

public override TEntity Attach(TEntity entity)
{
return set.Attach(entity);
}

public override TEntity Create()
{
return set.Create();
}

public override TDerivedEntity Create<TDerivedEntity>()
{
return set.Create<TDerivedEntity>();
}

public override TEntity Find(params object[] keyValues)
{
return set.Find(keyValues);
}

public override Task<TEntity> FindAsync(params object[] keyValues)
{
return set.FindAsync(keyValues);
}

public override Task<TEntity> FindAsync(CancellationToken cancellationToken, params object[] keyValues)
{
return set.FindAsync(cancellationToken, keyValues);
}

public override TEntity Remove(TEntity entity)
{
return set.Remove(entity);
}

public override IEnumerable<TEntity> RemoveRange(IEnumerable<TEntity> entities)
{
return set.RemoveRange(entities);
}

public override DbSqlQuery<TEntity> SqlQuery(string sql, params object[] parameters)
{
return set.SqlQuery(sql, parameters);
}

public override ObservableCollection<TEntity> Local
{
get { return set.Local; }
}

public override bool Equals(object obj)
{
return set.Equals(obj);
}

public override int GetHashCode()
{
return set.GetHashCode();
}

public override string ToString()
{
return set.ToString();
}

最后,我们必须使用拦截对象:
IEnumerator<TEntity> IEnumerable<TEntity>.GetEnumerator()
{
return intercepted.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return intercepted.GetEnumerator();
}

Type IQueryable.ElementType
{
get { return intercepted.ElementType; }
}

Expression IQueryable.Expression
{
get { return intercepted.Expression; }
}

IQueryProvider IQueryable.Provider
{
get { return intercepted.Provider; }
}

IDbAsyncEnumerator<TEntity> IDbAsyncEnumerable<TEntity>.GetAsyncEnumerator()
{
return ((IDbAsyncEnumerable<TEntity>)intercepted).GetAsyncEnumerator();
}

IDbAsyncEnumerator IDbAsyncEnumerable.GetAsyncEnumerator()
{
return ((IDbAsyncEnumerable<TEntity>)intercepted).GetAsyncEnumerator();
}

最后,我们可以使用普通的 DbContext .我们只需要覆盖它的 Set注入(inject)代理的方法:
public class MyContext : DbContext
{
public DbSet<Entity> Entities { get; set; }

public override DbSet<TEntity> Set<TEntity>()
{
return new DbSetProxy<TEntity>(base.Set<TEntity>());
}
}

关于linq - 拦截所有 EF6 Linq 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22714865/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com