用于将自定义表达式传递到where条件的实体框架查询的C#Linq Lambda表达式 [英] C# Linq Lambda Expression for Entity Framework Query Passing Custom Expression to Where Condition

查看:78
本文介绍了用于将自定义表达式传递到where条件的实体框架查询的C#Linq Lambda表达式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个表,分别称为ShipmentType和Books.实体类已为这些表映射.创建了另一个名为BookShipment的类,其中包含两个属性,即ShipmentType和Book的类.

I have two tables called ShipmentType and Books. Entity class has been mapped for these tables. Created another class called BookShipment which contains two properties, classes of ShipmentType and Book.

public class BookShipment
{
    public ShipmentType Shipment { get; set; }
    public Books Book { get; set; }
}

我试图创建如下的where表达式.

I was trying to create a where expression as follows.

Expression<Func<BookShipment, bool>> expr = x => (x.Shipment.ID == 1 && x.Book.ID == 1);

            var result = from c in styp
                         join d in book
                          on c.ID equals d.ID                         
                         select new BookShipment { Shipment = c, Book = d };

var List = result.Where(expr).ToList();

及以上where子句中的表达式正常工作,并从数据库中获取结果.

and above expression at where clause is working fine and getting the result from database.

试图创建一个与上述expr表达式相同的动态表达式,但是它给出了错误.

Tried to create a dynamic expression same as above expr expression but it is giving error.

BookShipment table = new BookShipment();
table.Shipment = new ShipmentType();
table.Book = new Books();

ParameterExpression ParameterL = Expression.Parameter(table.GetType(), "x");

ParameterExpression Parameter1 = Expression.Parameter(table.Shipment.GetType(), "x.Shipment");
ParameterExpression Parameter2 = Expression.Parameter(table.Book.GetType(), "x.Book");

var Property1 = Expression.Property(Parameter1, "ID");
var Property2 = Expression.Property(Parameter2, "ID");

var Clause1 = Expression.Equal(Property1, Expression.Constant(1));
var Clause2 = Expression.Equal(Property2, Expression.Constant(1));

var Lambda1 = Expression.Lambda<Func<ShipmentType, bool>>(Clause1, Parameter1);
var Lambda2 = Expression.Lambda<Func<Books, bool>>(Clause2, Parameter2);

var OrElseClause = Expression.Or(Lambda1.Body, Lambda2.Body);
var Lambda = Expression.Lambda<Func<BookShipment, bool>>(OrElseClause, ParameterL);

            var result = from c in styp
                         join d in book
                          on c.ID equals d.ID                         
                         select new BookShipment { Shipment = c, Book = d };

var record = result.Where(Lambda).ToList();

在执行Where子句时会给出错误.

When executing above Where clause it is giving error.

{System.InvalidOperationException: The LINQ expression 'DbSet<ShipmentType>
    .Join(
        outer: DbSet<Books>, 
        inner: s => s.ID, 
        outerKeySelector: b => b.BookID, 
        innerKeySelector: (s, b) => new TransparentIdentifier<ShipmentType, Books>(
            Outer = s, 
            Inner = b
        ))
    .Where(ti => ti.Shipment.ID == 1 || ti.Book.BookID == 1)' could not be translated.

推荐答案

在创建表达式以传递到LINQ where函数时,请遵循以下提示:

when you create an expression to pass into the LINQ where function, take the following hints:

类型为 Expression< Func< T,Bool>> ...

这意味着您拥有一个类型T的参数,并且返回了布尔值

that means you have ONE parameter of type T, and you return a bool

如果您创建两个具有这种类型的Lambda,并且想要将它们组合在一起...即使您将T作为参数使用相同的类型,则两个参数实例也不相同...您将不得不遍历树并替换参数,因此只有一个实例...

if you create two Lambdas with this type, and you want to combine them... even though you have the same type T as parameter, the two parameter instances are not the same ... you will have to traverse the tree and replace the parameter so there is only one instance...

如果您想要示例代码...在这里...

if you'd like an example code ... here you go...

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace SoExamples.ExpressionTrees
{
    class Program
    {
        static void Main(string[] args)
        {

            var expr1 = GetExpression<Func<A, bool>>(x => x.Prop1 == 42);
            var expr2 = GetExpression<Func<A, bool>>(x => x.Prop2 == "foo");
            var expr3 = GetConstComparison<A, int>("Prop3.Prop1", 123);

            var test = new A { Prop1 = 42, Prop2 = "foo", Prop3 = new B { Prop1 = 123 } };

            var f1 = expr1.Compile();
            var t1 = f1(test);
            var f2 = expr2.Compile();
            var t2 = f2(test);
            var f3 = expr3.Compile();
            var t3 = f3(test);

            Expression tmp = Expression.AndAlso(Expression.AndAlso(expr1.Body, expr2.Body), expr3.Body);
            tmp = new ParamReplaceVisitor(expr2.Parameters.First(), expr1.Parameters.First()).Visit(tmp);
            tmp = new ParamReplaceVisitor(expr3.Parameters.First(), expr1.Parameters.First()).Visit(tmp);
            var expr4 = Expression.Lambda<Func<A, bool>>(tmp, expr1.Parameters.First());

            var f4 = expr4.Compile();
            var t4 = f4(test);

            var list = new List<A> { test };

            var result = list.AsQueryable().Where(expr4).ToList();

        }

        static Expression<TDelegate> GetExpression<TDelegate>(Expression<TDelegate> expr)
        {
            return expr;
        }
        static Expression<Func<T, bool>> GetConstComparison<T, P>(string propertyNameOrPath, P value)
        {
            ParameterExpression paramT = Expression.Parameter(typeof(T), "x");
            Expression expr = getPropertyPathExpression(paramT, propertyNameOrPath.Split('.'));
            return Expression.Lambda<Func<T, bool>>(Expression.Equal(expr, Expression.Constant(value)), paramT);
        }

        private static Expression getPropertyPathExpression(Expression expr, IEnumerable<string> propertyNameOrPath)
        {
            var mExpr = Expression.PropertyOrField(expr, propertyNameOrPath.First());
            if (propertyNameOrPath.Count() > 1)
            {
                return getPropertyPathExpression(mExpr, propertyNameOrPath.Skip(1));
            }
            else
            {
                return mExpr;
            }
        }
    }

    public class ParamReplaceVisitor : ExpressionVisitor
    {
        private ParameterExpression orig;
        private ParameterExpression replaceWith;

        public ParamReplaceVisitor(ParameterExpression orig, ParameterExpression replaceWith)
        {
            this.orig = orig;
            this.replaceWith = replaceWith;
        }
        protected override Expression VisitParameter(ParameterExpression node)
        {
            if (node == orig)
                return replaceWith;
            return base.VisitParameter(node);
        }
    }

    public class A
    {
        public int Prop1 { get; set; }
        public string Prop2 { get; set; }
        public B Prop3 { get; set; }
    }

    public class B
    {
        public int Prop1 { get; set; }
    }
}

当然,您将要添加错误处理等...

of course you will want to add errorhandling etc...

这篇关于用于将自定义表达式传递到where条件的实体框架查询的C#Linq Lambda表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆