TL;DR:阅读第 1 点的示例。使用 QueryMap 中的代码,在下面以粗体进行更改。
是的,我已经设法通过对QueryMap的一些细微修改来解决这个问题
我需要做两件事:
弄清楚如何告诉 querymap 调用使用数据上下文的方法?
当通过接口访问时,弄清楚如何让 querymap 获取在类上定义的属性。
第一部分相当简单:
private static readonly ExpressionMethod<Func<AquaReportsRepository, string, bool>> _IsPhysicalItem =
ExpressionMethod.Create((AquaReportsRepository ardc, string i) => ardc._AquaReportsDC.Aqua_IsPhysicalItem(i) ?? true);
[MapToExpression("_IsPhysicalItem")]
public bool IsPhysicalItem(string itemNumber)
{
return _IsPhysicalItem.Invoke(this, itemNumber);
}
这里的关键是简单地使用一个函数,该函数将对象本身作为第一个参数(AquaReportsRepository
在这种情况下),以及正常的其他参数。
然而,第二部分需要对MappedQueryVisitor.cs
. 在这两种情况下,只有一个 if 语句(里面有语句!)。
用这个替换现有GetLambda
方法:
private LambdaExpression GetLambda(Expression receiver, MemberInfo member) {
LambdaExpression exp;
if(!_mappings.TryGetValue(member, out exp)) {
exp = _mappingLookup(member);
if(null == exp) {
var attr = (MapToExpressionAttribute) member.GetCustomAttributes(typeof(MapToExpressionAttribute), true).FirstOrDefault();
// Added by me to deal with interfaces
if (null == attr)
{
if (null != receiver)
{
// member could be an interface's member, so check the receiver.object type
if (receiver.NodeType == ExpressionType.Constant)
{
var receiverType = ((ConstantExpression)receiver).Value.GetType();
var receiverMemberInfo = receiverType.GetMembers().Where(mi => mi.Name == member.Name).SingleOrDefault();
if (null != receiverMemberInfo)
{
attr = (MapToExpressionAttribute)receiverMemberInfo.GetCustomAttributes(typeof(MapToExpressionAttribute), true).FirstOrDefault();
member = receiverMemberInfo;
}
}
}
}
if(null != attr) {
exp = GetLambdaFromAttribute(receiver, member.DeclaringType, attr);
}
}
_mappings.Add(member, exp);
}
return exp;
}
这种变化意味着如果我们有一个member
MethodInfo
表示接口方法的对象,我们将识别它并尝试获取MethodInfo
我们正在使用的具体类型的实际类型(由常量表达式定义)。
现在它正确地获取了MapToExpressionAttribute
实现类的属性,给定MemberInfo
一个接口。
下一个问题是 with VisitMethodCall
,因为参数表达式是接口类型,所以从属性调用替换表达式失败,我们调用的方法需要实现类。
最后的代码更改纠正了这一点。
将CollectArguments
方法更改为此:
private static IEnumerable<Expression> CollectArguments(MethodCallExpression m) {
IEnumerable<Expression> args = m.Arguments;
if (!m.Method.IsStatic)
{
var objectExpression = m.Object;
// Added by me, to deal with interfaces
if (objectExpression.NodeType == ExpressionType.Constant)
{
var objectConstExpression = ((ConstantExpression)objectExpression);
if (objectConstExpression.Type.IsInterface)
{
objectExpression = Expression.Constant(objectConstExpression.Value);
}
}
args = Enumerable.Repeat(objectExpression, 1).Concat(args);
}
return args;
}