我有以下自定义类型,其上有一个方法来确定一个时间跨度是否与另一个
重叠public struct DateTimeSpan
{
public DateTime? Start { get; set; }
public DateTime? End { get; set; }
public bool Overlaps(DateTimeSpan overlap)
{
//....
}
}
我正在尝试编写一个自定义HQL生成器,以便在我的数据访问LINQ查询中使用此方法时,它将在查询数据库时生成适当的SQL。
这是我的BaseHqlGeneratorForMethod
尝试比较一个End
的{{1}}属性与另一个<{p}}的开头
DateTimeSpan
我已经证明public class DateSpanOverlapsDateTimeSpanHqlGenerator : BaseHqlGeneratorForMethod
{
public DateSpanOverlapsDateTimeSpanHqlGenerator()
{
SupportedMethods = new[]
{
ReflectionHelper.GetMethodDefinition<DateTimeSpan>(x => x.Overlaps(new DateTimeSpan()))
};
}
public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder builder, IHqlExpressionVisitor visitor)
{
var endTargetProperty = ReflectionHelper.GetProperty<DateTimeSpan, DateTime?>(x => x.End);
Expression endTargetExpression = Expression.MakeMemberAccess(targetObject, endTargetProperty);
var endArgumentProperty = ReflectionHelper.GetProperty<DateTimeSpan, DateTime?>(x => x.End);
Expression endArgumentExpression = Expression.MakeMemberAccess(arguments[0], endArgumentProperty);
return builder.GreaterThanOrEqual(visitor.Visit(endTargetExpression).AsExpression(), visitor.Visit(endArgumentExpression).AsExpression());
}
}
中的End
属性被评估为正常,但无论我做什么,我都无法评估targetObject
中的End
属性。上面的代码只是我尝试的一个例子(并且看起来最明显,因为它适用于arguments[0]
)我尝试以targetObject
Antlr.Runtime.NoViableAltException
和targetObject
之间的一个明显不同之处是arguments[0]
的类型为targetObject
,而PropertyExpression
的类型为arguments[0]
。我认为这意味着需要有不同的方式来访问它们,但我无法弄清楚它是什么!
答案 0 :(得分:2)
treeBuilder.Constant(arg.SubProperty);将缓存您的对象,以便在运行查询时最终会出现问题。
你应该在DateTimeSpan中添加一个重载
public bool Overlaps(DateTime? start, DateTime? end)
将签名匹配到DateSpanOverlapsDateTimeSpanHqlGenerator
SupportedMethods = new[]
{
ReflectionHelper.GetMethodDefinition<DateTimeSpan>(span => span.Overlaps(default(DateTime?), default(DateTime?)))
};
并以这种方式获取值:
public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder builder, IHqlExpressionVisitor visitor)
{
var startProperty = ReflectionHelper.GetProperty<DateTimeSpan, DateTime?>(x => x.Start);
var endProperty = ReflectionHelper.GetProperty<DateTimeSpan, DateTime?>(x => x.End);
MemberExpression targetStartExpression = Expression.MakeMemberAccess(targetObject, startProperty);
MemberExpression targetEndExpression = Expression.MakeMemberAccess(targetObject, endProperty);
HqlExpression startDateExpression = visitor.Visit(arguments[0]).AsExpression();
HqlExpression endDateExpression = visitor.Visit(arguments[1]).AsExpression();
....
}
在照常营业之后:
builder.LessThanOrEqual(visitor.Visit(targetStartExpression).AsExpression(), endDateExpression)
答案 1 :(得分:0)
我不知道你是否曾经解决这个问题,或者仍然对答案感兴趣,但是我在寻找这个确切问题的解决方案时偶然发现了这个问题,所以我想我会为其他人添加我的解决方案。
调试时我注意到目标对象参数是作为PropertyExpression
类型的表达式传入的,而我的参数是作为ConstantExpression
的类型传入的,所以虽然它完全有效添加到使用PropertyExpression
的{{1}},不能使用常量值。
相反,我提取常量的值并直接访问子属性的值,创建新的常量表达式,然后我可以使用它来构建查询表达式。
我不知道这是否是最佳或最优雅的方式,但它对我有用。我希望它有所帮助。
Expression.Property