【发布时间】:2017-03-02 09:42:34
【问题描述】:
我有通用商业服务(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");
错误:
运算符“Equal”的操作数与方法“op_Equality”的参数不匹配。
如何将参数作为值传递?
谢谢。
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);
}
}
}
【问题讨论】:
-
你还没有通过
Visitor类展示你在在做什么。你能发一个minimal reproducible example来证明这个问题吗? -
您的
Visitor班级在做什么?为什么要修改表达式? -
因为 UserDT 类是我在应用程序中使用的数据传输对象。用户类是实体框架创建的类。 Visitor Class是一个遍历所有Expression节点(UserDT)并创建新的User节点类型的类。
-
您转储了一些代码,但没有多大帮助。需要的是一些代码,我们可以复制、粘贴、按 F5 并立即重现您的问题。在某些情况下这是不可能的,但在你的情况下它是。
-
调试您的
VisitMember方法。在第二种情况下,它将为psw和username变量调用,因为编译器会将它们转换为闭包类的字段。您对需要原样返回的成员做错了 - 在这种情况下,您确实应该调用并返回基本实现,但您不这样做。
标签: c# entity-framework lambda expression-trees