简体   繁体   English

实体框架查询的 C# Linq Lambda 表达式将自定义表达式传递给 Where 条件

[英]C# Linq Lambda Expression for Entity Framework Query Passing Custom Expression to Where Condition

I have two tables called ShipmentType and Books.我有两个名为 ShipmentType 和 Books 的表。 Entity class has been mapped for these tables.已为这些表映射实体类。 Created another class called BookShipment which contains two properties, classes of ShipmentType and Book.创建了另一个名为 BookShipment 的类,其中包含两个属性,即 ShipmentType 和 Book 类。

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

I was trying to create a where expression as follows.我试图创建一个 where 表达式如下。

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();

and above expression at where clause is working fine and getting the result from database.和上述 where 子句的表达式工作正常并从数据库中获取结果。

Tried to create a dynamic expression same as above expr expression but it is giving error.试图创建一个与上述 expr 表达式相同的动态表达式,但它给出了错误。

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();

When executing above Where clause it is giving error.在执行上述 Where 子句时,它给出了错误。

{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.

when you create an expression to pass into the LINQ where function, take the following hints:创建表达式以传递到 LINQ where 函数时,请注意以下提示:

the type is Expression<Func<T,Bool>> ...类型是Expression<Func<T,Bool>> ...

that means you have ONE parameter of type T, and you return a bool这意味着你有一个 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...如果您使用这种类型创建两个 Lambda,并且您想将它们组合起来……即使您具有相同的类型 T 作为参数,这两个参数实例也不相同……您将不得不遍历树并替换参数所以只有一个实例...

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...当然你会想要添加错误处理等......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM