gpt4 book ai didi

.net - 从一个重要的 IQueryable 编译 Linq 到 SQL 查询

转载 作者:行者123 更新时间:2023-12-04 15:49:29 27 4
gpt4 key购买 nike

有没有办法使用 CompiledQuery.Compile 方法来编译与 IQueryable 关联的表达式?目前我有一个 IQueryable,后面有一个非常大的表达式树。 IQueryable 是使用几种方法构建的,每种方法都提供组件。例如,两种方法可能会返回 IQueryables,然后将它们连接到第三个中。由于这个原因,我不能在 compile() 方法调用中明确定义整个表达式。

我希望将表达式作为 someIQueryable.Expression 传递给 compile 方法,但是该表达式不是 compile 方法所需的形式。如果我尝试通过将查询直接放入 compile 方法来解决此问题,例如:

    var foo = CompiledQuery.Compile<DataContext, IQueryable<User>>(dc => dc.getUsers());
var bar = foo(this);

在数据上下文中进行调用表单的地方,我收到一条错误消息,指出“getUsers 未映射为存储过程或用户定义的函数”。同样,我不能只将 getUsers 方法的内容复制到我进行编译调用的位置,因为它又会使用其他方法。

有什么方法可以将从“getUsers”返回的 IQueryable 上的表达式传递给 Compile 方法?

更新
我尝试使用以下代码将我的意志强加于系统:
    var phony = Expression.Lambda<Func<DataContext, IQueryable<User>>>(
getUsers().Expression, Expression.Parameter(typeof(DataContext), "dc"));

Func<DataContext, IQueryable<User>> wishful = CompiledQuery.Compile<DataContext, IQueryable<User>>(phony);
var foo = wishful(this);

foo 最终成为:

{System.Data.Linq.SqlClient.SqlProvider+OneTimeEnumerable`1[Model.Entities.User]}

我没有在 foo 中查看结果的选项,因为没有提供扩展结果并运行查询,我只看到消息“操作可能破坏运行时”。

我只需要找到一种方法让 sql 字符串只生成一次并在后续请求中用作参数化命令,我可以在数据上下文中使用 GetCommand 方法手动执行此操作,但随后我必须显式设置所有参数并自己进行对象映射,考虑到这个特定查询的复杂性,这是几百行代码。

更新

John Rusk 提供了最有用的信息,所以我授予他在这方面的胜利。但是,需要进行一些额外的调整,并且我在此过程中遇到了其他一些问题,所以我想我会“扩展”答案。首先,“操作可能破坏运行时”错误不是由于表达式的编译,它实际上是由于表达式树中的一些深度转换。在某些地方我需要调用 .Cast<T>()正式类型转换项目的方法,即使它们是正确的类型。无需过多详细说明,当几个表达式组合成一棵树并且每个分支都可以返回不同的类型时,这基本上是必需的,它们都是公共(public)类的子类型。

解决了不稳定的问题后,我回到了编译问题。约翰的扩展解决方案几乎就在那里。它在树中查找方法调用表达式,并尝试将它们解析为该方法通常返回的底层表达式。我对表达式的引用不是由方法调用提供的,而是由属性提供的。所以我需要修改执行扩展的表达式访问者以包含这些类型:
protected override Expression VisitMemberAccess(MemberExpression m) {
if(m.Method.DeclaringType == typeof(ExpressionExtensions)) {
return new ExpressionExpander().Visit((Expression)(((System.Reflection.PropertyInfo)m.Member).GetValue(null, null)));
}
return base.VisitMemberAccess(m);
}

这种方法可能并不适用于所有情况,但它应该可以帮助任何发现自己处于同样困境的人。

最佳答案

至少在我的测试中,这样的东西是有效的:

Expression<Func<DataContext, IQueryable<User>> queryableExpression = GetUsers();
var expressionWithSomeAddedStuff = (DataContext dc) => from u in queryableExpression.Invoke(dc) where ....;
var expressionThatCanBeCompiled = expressionWithSomeAddedStuff.Expand();
var foo = CompiledQuery.Compile<DataContext, IQueryable<User>>(expressionThatCanBeCompiled);

这看起来有点冗长,您可能可以进行一些改进。

他们的关键点是它使用了来自 LinqKit 的 Invoke 和 Expand 方法。它们基本上让您通过组合构建查询,然后编译完成的结果。

关于.net - 从一个重要的 IQueryable 编译 Linq 到 SQL 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/680295/

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