【问题标题】:Expression tree gives error when used with parameters C#. But works fine with values表达式树与参数 C# 一起使用时会出错。但适用于价值观
【发布时间】: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 方法。在第二种情况下,它将为pswusername 变量调用,因为编译器会将它们转换为闭包类的字段。您对需要原样返回的成员做错了 - 在这种情况下,您确实应该调用并返回基本实现,但您不这样做。

标签: c# entity-framework lambda expression-trees


【解决方案1】:

您的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);
}

【讨论】:

    猜你喜欢
    • 2021-12-24
    • 1970-01-01
    • 1970-01-01
    • 2013-10-24
    • 1970-01-01
    • 2012-05-18
    • 1970-01-01
    • 1970-01-01
    • 2013-05-01
    相关资源
    最近更新 更多