【发布时间】:2013-08-21 03:31:52
【问题描述】:
我正在使用 ServiceStack ORMLite,需要执行如下查询:
SqlServerExpressionVisitor<Contact> sql = new SqlServerExpressionVisitor<Contact>();
SqlServerExpressionVisitor<Account> accSql = new SqlServerExpressionVisitor<Account>();
var finalSql = sql.Where(a=>
(from a1 in accSql where a1.Type == "Client"
&& a1.Id==a.AccountId select a1).Any());
执行此查询时,我得到一个 lambda 错误“a”未在范围内定义。这里的“a”是对父 Where 方法调用定义的变量的引用。
如何使用 ExpressionVisitor 在 WHERE 子句中执行子查询?
更新: 我创建了自己的 SqlServiceExpressionVisitor,它允许我自定义 ORM 生成 SQL 语句的方式。我还添加了如下类:
public static class SQL
{
public static bool ExistsIn<T>(T Value, string subquery, params T[] parameters)
{
return true;
}
public static bool ExistsIn<T, TItem>(T Value, SqlExpressionVisitor<TItem> innerSql)
{
return true;
}
public static SqlExpressionVisitor<T> Linq<T>()
{
return OrmLiteConfig.DialectProvider.ExpressionVisitor<T>();
}
}
然后扩展 VisitMethodCall 以考虑我的新类并相应地调用我的自定义方法:
internal object VisitSQLMethodCall(MethodCallExpression m)
{
string methodName = m.Method.Name;
if (methodName == "ExistsIn")
{
string quotedColName = Visit(m.Arguments[0] as Expression).ToString();
dynamic visit = Visit(m.Arguments[1]);
string innerQuery = (visit is string) ? visit.ToString().Trim('"') : visit.ToSelectStatement();
if (m.Arguments[2] != null)
{
List<object> fields = VisitExpressionList((m.Arguments[2] as NewArrayExpression).Expressions);
int count = 0;
foreach (var field in fields)
{
innerQuery = innerQuery.Replace("@" + count.ToString(), field.ToString());
count++;
}
}
return new PartialSqlString(string.Format("{0} IN ({1})", quotedColName, innerQuery));
}
}
结果很有希望,下面是它的使用方法:
.Where(a => SQL.ExistsIn(a.AccountId, SQL.Linq<Account>()
.Where(acc => acc.Name.Contains("a")).Select(acc => acc.Id)))
上面生成正确的内部 SQL,但是如果我包含来自父查询的引用,系统再次调用 return Expression.Lambda(m).Compile().DynamicInvoke();产生相同的错误!
SQL.Linq<Contact>().Where(a => SQL.ExistsIn(a.AccountId, SQL.Linq<Account>()
.Where(acc => acc.Id == a.AccountId).Select(acc => acc.Id)))
以上产生错误:参数“a”未在范围内定义。 我想我只需要以某种方式在我的自定义方法中的第二次访问调用中添加一个参数定义,但我还没有弄清楚怎么做! 任何帮助表示赞赏!
【问题讨论】:
-
虽然我知道ORMLite新版本可以处理连接,但我宁愿使用另一个ORM比如Dapper来解决两个或多个表之间的连接。我发现 Dapper 在这方面更强大。
-
我在 Dapper 上没有看到任何支持 Linq to SQL 的文档。另外我觉得我对 ORMLite 代码理解得更好,写得也很好。
标签: linq-to-sql servicestack ormlite-servicestack