我有通用商业服务(BS)课程。我使用这个BS类从DB获取数据。为了获取我发送给它的数据Expression.This Expression是用DTO对象创建的。 BS使用Custome Visitor Class将其转换为EF对象。 当我发送带有值的表达式时(如下)
Expression<Func<UserDT, bool>> t = x => x.Username == "tebo" && x.Password =="ICy5YqxZB1uWSwcVLSNLcA==" && x.Company.Id == new Guid("D88F5A20-5FBE-47FA-B3C0-B7F1241C0D45");
我得到数据。有用。但是,如果我想获取带参数的数据,我会收到错误
var psw = "ICy5YqxZB1uWSwcVLSNLcA==";
string username = "tebo";
Expression<Func<UserDT, bool>> t = x => x.Username == username && x.Password == psw && x.Company.Id == new Guid("D88F5A20-5FBE-47FA-B3C0-B7F1241C0D45");
错误:
运营商的操作数&#39; Equal&#39;不匹配方法的参数&#39; op_Equality&#39;。
如何将参数作为值传递?
谢谢。
using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq.Expressions;
namespace CXFServer.Net.Test.UTest.MyTest
{
/// <summary>
/// Summary description for StackOverFlow
/// </summary>
[TestClass]
public class StackOverFlow
{
[TestMethod]
public void TestingWithoutParameters()
{
Expression<Func<UserDT, bool>> t = x => x.Username == "tebo" && x.Password == "ICy5YqxZB1uWSwcVLSNLcA==" && x.Company.Id == new Guid("D88F5A20-5FBE-47FA-B3C0-B7F1241C0D45");
var expectedUserDt = new UserBS().Login(t);
Assert.IsTrue(expectedUserDt);
}
[TestMethod]
public void TestingWithParameters()
{
var psw = "ICy5YqxZB1uWSwcVLSNLcA==";
string username = "tebo";
Expression<Func<UserDT, bool>> t = x => x.Username == username && x.Password == psw && x.Company.Id == new Guid("D88F5A20-5FBE-47FA-B3C0-B7F1241C0D45");
var expectedUserDt = new UserBS().Login(t);
Assert.IsTrue(expectedUserDt);
}
}
class User
{
public System.Guid UserId { get; set; }
public string UserFirstName { get; set; }
public string UserLastName { get; set; }
public string UserEmail { get; set; }
public string UserUsername { get; set; }
public string UserPassword { get; set; }
public Nullable<int> UserRole { get; set; }
public Guid User_CompanyId { get; set; }
public Nullable<System.DateTime> UserModifyDate { get; set; }
public Nullable<bool> UserStatus { get; set; }
}
class UserDT
{
public Guid Id
{
get;
set;
}
public bool Status
{
get;
set;
}
public DateTime ModifyDate
{
get;
set;
}
public string FirstName
{
get;
set;
}
public string LastName
{
get;
set;
}
public string Email
{
get;
set;
}
public string Username
{
get;
set;
}
public string Password
{
get;
set;
}
public int Role
{
get;
set;
}
public CompanyDT Company
{
get;
set;
}
}
class CompanyDT : BaseDT
{
public string Name
{
get;
set;
}
}
class BaseDT
{
public Guid Id
{
get;
set;
}
public bool Status
{
get;
set;
}
public DateTime ModifyDate
{
get;
set;
}
}
class BaseBS<UserDT, User>
{
public bool FindBy(Expression<Func<UserDT, bool>> predicateDt)
{
//parameter that will be used in generated expression
var param = Expression.Parameter(typeof(User));
var visitor = new Visitor<UserDT, User>(param);
var body = visitor.Visit(predicateDt.Body);
//Expression body = new AToBConverter<T, E>(DataTransformation.DataTransformation.QueryMappings).Visit(predicateDt);
Expression<Func<User, bool>> predicate = Expression.Lambda<Func<User, bool>>(body, param);
//Expression<Func<E, bool>> predicate = (Expression<Func<E, bool>>)(body,param);
//IQueryable<User> query = ContextFactory.Retrieve().Set<User>().Where(predicate);
return true;
}
}
class Visitor<T, E> : ExpressionVisitor
{
ParameterExpression _parameter;
//there must be only one instance of parameter expression for each parameter
//there is one so one passed here
public Visitor(ParameterExpression parameter)
{
_parameter = parameter;
}
//this method replaces original parameter with given in constructor
protected override Expression VisitParameter(ParameterExpression node)
{
return _parameter;
}
protected override Expression VisitConstant(ConstantExpression node)
{
return base.VisitConstant(node);
}
//protected override visi
//this one is required because PersonData does not implement IPerson and it finds
//property in PersonData with the same name as the one referenced in expression
//and declared on IPerson
protected override Expression VisitMember(MemberExpression node)
{
if (node.Type.Name.IndexOf("DT") > -1)
{
return Visit(node.Expression);
}
if (node.Member.MemberType != System.Reflection.MemberTypes.Property)
{
return Visit(node.Expression);
}
//throw new NotImplementedException();
string memberName = string.Empty;
if (node.Type.Name.IndexOf("DT") > -1)
{
}
else
{
if (node.Expression.Type.Name.IndexOf("DT") > 0 && node.Expression.Type.Name.Substring(0, node.Expression.Type.Name.IndexOf("DT")) != typeof(E).Name)
{
string type = node.Expression.Type.Name.Substring(0, node.Expression.Type.Name.IndexOf("DT"));
memberName = typeof(E).Name + "_" + type + "Id";
}
else
{
memberName = typeof(E).Name + node.Member.Name;
}
}
//name of a member referenced in original expression in your
//sample Id in mine Prop
//var memberName = node.Member.Name;
//find property on type T (=PersonData) by name
var otherMember = typeof(E).GetProperty(memberName);
//visit left side of this expression p.Id this would be p
var inner = Visit(node.Expression);
return Expression.Property(inner, otherMember);
}
}
class UserBS : BaseBS<UserDT, User>
{
public UserBS()
: base()
{
}
public bool Login(Expression<Func<UserDT, bool>> predicateDt)
{
return FindBy(predicateDt);
}
}
}
答案 0 :(得分:2)
很难遵循VisitMember
的逻辑,但主要问题是以下分支:
if (node.Member.MemberType != System.Reflection.MemberTypes.Property)
{
return Visit(node.Expression);
}
这意味着,如果您有obj.field
,则会转换为obj
,这是不正确的。
当你使用常量时,代码永远不会达到那个条件,这就是它工作的原因。但是,当表达式使用捕获的变量(闭包)时,它确实存在,这就是它不起作用的原因。
修复是通过调用基本实现来正确处理大小写:
if (node.Member.MemberType != System.Reflection.MemberTypes.Property)
{
return base.VisitMember(node);
}