这里有没有人有编写自定义Linq提供程序的经验?
我要做的是判断作为业务对象属性的MemberExpression是否应该包含在SQL中,还是作为常量处理,因为它来自恰好是业务对象的本地变量
例如,如果你有这个:
Customer c = LoadCustomerFromDatabase();
var orders = from o in db.Orders() where o.CustomerID == c.CustomerID select o;
目前,我的查询翻译器会尝试执行SELECT * FROM orders o where o.CustomerID = c.CustomerID
,这当然不起作用。
我想做的是检查c.CustomerID
上的MemberExpression,并尝试找出它是一个局部变量,还是只是用作Linq表达式的一部分。
我已经设法将其作为查询的第二遍,查找SQL Server无法绑定的字段,并注入其值,但如果可能的话,我想让它全部发生在同一时间。我试着查看表达式Type
属性和IsAutoClass
,但这只是猜测,因为它包含单词Auto。它不起作用:))
答案 0 :(得分:1)
好吧,我不知道你是否可以把它减少到一遍,但是你可以获得有关该成员的信息,如果它与另一个你声明属于查询的变量一致(在这种情况下“ o“),你用它来生成你的查询。
否则,您会认为它是常量,然后将该值插入。
不幸的是,因为您可以在查询的多个位置使用语句(除了let语句之外),因此您似乎只能在一次传递中执行此操作,因为您需要知道所有查询变量在前面。
答案 1 :(得分:1)
好的,经过一些快速的统计分析(即手动比较各个属性),DeclaringType,ReflectedType和Namespace是Lambda参数不在范围内时“触发。”
因此,除非有人提出更好的答案,否则我可能会继续这样做。
答案 2 :(得分:1)
在Where表达式中,您正在查看Expression<Func<T,bool>>
- 这意味着最外层的lambda应该只有一个ParameterExpression
类型T
。
如果比较与行有关,则它将具有(作为祖先)ParameterExpression
;如果它是局部变量,它将具有(作为祖先)ConstantExpression
- 但是,此常量表达式的类型将由编译器生成,以处理表达式中使用的所有捕获变量。
像这样:
using System;
using System.Linq.Expressions;
class Foo
{
public string Name { get; set; }
static void Main()
{
var exp = (LambdaExpression) GetExpression();
WalkTree(0, exp.Body, exp.Parameters[0]);
}
static void WriteLine(int offset, string message)
{
Console.WriteLine(new string('>',offset) + message);
}
static void WalkTree(int offset, Expression current,
ParameterExpression param)
{
WriteLine(offset, "Node: " + current.NodeType.ToString());
switch (current.NodeType)
{
case ExpressionType.Constant:
WriteLine(offset, "Constant (non-db)"
+ current.Type.FullName);
break;
case ExpressionType.Parameter:
if (!ReferenceEquals(param, current))
{
throw new InvalidOperationException(
"Unexpected parameter: " + param.Name);
}
WriteLine(offset, "db row: " + param.Name);
break;
case ExpressionType.Equal:
BinaryExpression be = (BinaryExpression)current;
WriteLine(offset, "Left:");
WalkTree(offset + 1, be.Left, param);
WriteLine(offset, "Right:");
WalkTree(offset + 1, be.Right, param);
break;
case ExpressionType.MemberAccess:
MemberExpression me = (MemberExpression)current;
WriteLine(offset, "Member: " + me.Member.Name);
WalkTree(offset + 1, me.Expression, param);
break;
default:
throw new NotSupportedException(
current.NodeType.ToString());
}
}
static Expression<Func<Foo, bool>> GetExpression()
{
Foo foo = new Foo { Name = "abc" };
return row => row.Name == foo.Name;
}
}