Create predicate with a BinaryExpression containing multiple parameters

前端 未结 3 607
旧巷少年郎
旧巷少年郎 2021-01-27 10:52

is it possible to dynamically generate such a predicate using LambdaExpressions?

Expression> predicate = t =>
    t         


        
3条回答
  •  不知归路
    2021-01-27 11:11

    I would recommend using nein-linq to combine, build and compose predicates (and many other expression puzzles), or LinqKit

    Both support Entity Framework

    For example, using nein-linq

    Given:

    public static class TestExpressions
    {
        [InjectLambda]
        public static bool IsTestDateEarlierThan(this Test test, DateTime? dateTime, int numberOfDays)
        {
            return dateTime > test.TestDate.AddDays(numberOfDays);
        }
    
        public static Expression> IsTestDateEarlierThan()
        {
            return (test, dateTime, numberOfDays) => dateTime > DbFunctions.AddDays(test.TestDate, numberOfDays);
        }
    
        // Simple caching...
        private static readonly Func _hasAnyLevelDateAfterTestDays = HasAnyLevelDateAfterTestDays().Compile();
    
        [InjectLambda]
        public static bool HasAnyLevelDateAfterTestDays(this Test test, int numberOfDays)
        {
            return _hasAnyLevelDateAfterTestDays(test, numberOfDays);
        }
    
        public static Expression> HasAnyLevelDateAfterTestDays()
        {
            return (test, numberOfDays) => test.Levels.Any(l => l.LevelDetails.Any(ld => test.IsTestDateEarlierThan(ld.LevelDate, numberOfDays)));
        }       
    }
    

    When:

    var testList = new List
    {
        new Test {
            Levels = new List {
                new Level {
                    LevelDetails = new List {
                        new LevelDetail {
                            LevelDate = DateTime.Today
                        }
                    }
                }
            },
            // Not matched
            TestDate = DateTime.Today
        },
        new Test {
            Levels = new List {
                new Level {
                    LevelDetails = new List {
                        new LevelDetail {
                            LevelDate = DateTime.Today
                        }
                    }
                }
            },
            // Not matched
            TestDate = DateTime.Today.AddDays(-1)
        },
        new Test {
            Levels = new List {
                new Level {
                    LevelDetails = new List {
                        new LevelDetail {
                            LevelDate = DateTime.Today
                        }
                    }
                }
            },
            // Matched
            TestDate = DateTime.Today.AddDays(-2)
        }
    };
    

    Then:

    var testQuery = testList.AsQueryable();
    
    // Alternative one
    var result1 = testQuery
        .ToInjectable() // Don't forget!!
        .Where(test => test.Levels.Any(l => l.LevelDetails.Any(ld => test.IsTestDateEarlierThan(ld.LevelDate, 1))))
        .ToList();
    
    // Alternative two: You get the point :)
    var result2 = testQuery
        .ToInjectable() // Don't forget!!
        .Where(test => test.HasAnyLevelDateAfterTestDays(1))
        .ToList();
    

提交回复
热议问题