Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/codeigniter/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Entity framework core 如何将运行时参数传递给EF核心谓词表达式_Entity Framework Core_Expression Trees_Predicatebuilder - Fatal编程技术网

Entity framework core 如何将运行时参数传递给EF核心谓词表达式

Entity framework core 如何将运行时参数传递给EF核心谓词表达式,entity-framework-core,expression-trees,predicatebuilder,Entity Framework Core,Expression Trees,Predicatebuilder,在一个使用EF核心的应用程序中,我试图通过创建谓词表达式的可重用库来消除查询代码的重复。然而,我正在努力处理接受运行时参数的谓词 让我们假设父子关系中有两个简单的实体类: public class Parent { public double Salary { get; set; } public ICollection<Child> Children { get; set; } } public class Child { public double S

在一个使用EF核心的应用程序中,我试图通过创建谓词表达式的可重用库来消除查询代码的重复。然而,我正在努力处理接受运行时参数的谓词

让我们假设父子关系中有两个简单的实体类:

public class Parent
{
    public double Salary { get; set; }
    public ICollection<Child> Children { get; set; }

}

public class Child
{
    public double Salary { get; set; }
}
我可以使用传统的EF Core查询检索所有孩子收入高于他们的父母,如下所示:

return Context.Set<Parent>()
    .Where(parent => parent.Children.Any(child =>
        child.Salary > parent.Salary));
private Expression<Func<Child, Parent, bool>> EarnsMoreThanParent = (Child child, Parent parent) => child.Salary > parent.Salary;
如果我想为上述查询创建一个可重用的谓词,我想它可能是这样的:

return Context.Set<Parent>()
    .Where(parent => parent.Children.Any(child =>
        child.Salary > parent.Salary));
private Expression<Func<Child, Parent, bool>> EarnsMoreThanParent = (Child child, Parent parent) => child.Salary > parent.Salary;
上面的谓词可以编译,但我还没有找到任何方法来使用它。问题是如何在运行时将父实体传递给它。这不会编译:

return _context.Set<Parent>()
    .Where(parent => parent.Children.Any(child =>
        EarnsMoreThanParent(child, parent));
我知道我将表达式和Func语法混为一谈,但我认为这是一个相对常见的要求,必须是可能的


谢谢

您可以尝试像这样包装整个表达式

private Expression<Func<Parent, bool>> EarnsMoreThanParent = 
    (Parent parent) => parent.Children.Any(child => child.Salary > parent.Salary)
然后用在整个哪里

return _context.Set<Parent>().Where(EarnsMoreThanParent);
代码的问题在于,在.Whereparent=>parent.Children.Anychild=>EarnsMoreThanParentchild中,parent中的整个表达式是一个表达式。因此,不会调用您的方法EarnsMoreThanParent,因为它是Where表达式的一部分,而EF将尝试将其解析为表达式,并且将失败


但是,是的,如果你需要将两个这样的条件与不同的条件组合起来,或者它可能不起作用,因为它会像where或more parent那样。where其他条件和所有条件都将被转换为和

你可以试着像这样包装整个表达式

private Expression<Func<Parent, bool>> EarnsMoreThanParent = 
    (Parent parent) => parent.Children.Any(child => child.Salary > parent.Salary)
然后用在整个哪里

return _context.Set<Parent>().Where(EarnsMoreThanParent);
代码的问题在于,在.Whereparent=>parent.Children.Anychild=>EarnsMoreThanParentchild中,parent中的整个表达式是一个表达式。因此,不会调用您的方法EarnsMoreThanParent,因为它是Where表达式的一部分,而EF将尝试将其解析为表达式,并且将失败


但是,是的,如果你需要将两个这样的条件与不同的条件结合起来,或者它可能不起作用,就像Whereans大于Parent一样。Wheres其他条件和所有这些条件都将被翻译成和

这是一个有趣的话题,主要是因为这么多年来,C语言都没有提供一种用于组合表达式的语法,例如类似于字符串插值的语法。许多第三方软件包都试图通过提供自定义扩展方法来解决这个问题,最终通过注入查询提供程序所需的实际表达式来转换查询表达式树

因为您已经用[predicatebuilder]标记了您的问题,所以我假设您正在使用提供自定义调用方法的包。它可用于调用表达式:

return\u context.Set .Whereparent=>parent.Children.Anychild=> EarnsMoreThanParent.Invokechild,parent .可扩展的; 被调用的表达式不能来自属性或方法的限制之外的缺点是,您必须使用这样的调用为每个查询调用AsExpandable。。。调用,否则自定义方法将不会生效,并且您将获得方法不受支持的运行时异常

最近我发现了一个非常有用的包,名为,它允许您以更自然的方式实现代码重用。不使用可重用表达式,而是使用常规OOP可重用原语,如computed get only属性和instance/static/extension方法,并简单地用[Decompile]属性标记它们。e、 g.在某些公共静态类中:

[反编译] public static bool earnsmorethanparenthis Child,Parent Parent=>Child.Salary>Parent.Salary; 或者在儿童班:

[反编译] public bool earnsMorthanParentParent=>this.Salary>parent.Salary; 然后,您只需在查询的某个点调用反编译自定义扩展方法:

return\u context.Set .Whereparent=>parent.Children.Anychild=> child.earnsmorethan父母 .反编译; 这看起来比使用表达式要好得多。缺点与其他解决方案相同——需要为每个查询调用自定义方法。在我对的回答中,我展示了一个将包插入EF Core 3.1查询处理管道的解决方案,我希望在未来EF Core中有类似的公共扩展点,它将消除那里需要的大量样板代码,这将提供最好的使用OOP功能,在表达式树和转换扩展中,替换为实际表达式,使其透明。e、 g.如前所述,插入DelegateDecompiler后,查询与为LINQ to对象编写的查询一样简单:

return\u context.Set .Whereparent=>parent.Children.Anychild=> child.earnsmorethan父母;
这是一个有趣的话题,主要是因为这么多年来,C没有提供用于组合表达式的语法,例如类似于字符串插值的语法。许多第三方软件包都试图解决i 通过提供自定义扩展方法,该方法在最后通过注入查询提供程序所需的实际表达式来转换查询表达式树

因为您已经用[predicatebuilder]标记了您的问题,所以我假设您正在使用提供自定义调用方法的包。它可用于调用表达式:

return\u context.Set .Whereparent=>parent.Children.Anychild=> EarnsMoreThanParent.Invokechild,parent .可扩展的; 被调用的表达式不能来自属性或方法的限制之外的缺点是,您必须使用这样的调用为每个查询调用AsExpandable。。。调用,否则自定义方法将不会生效,并且您将获得方法不受支持的运行时异常

最近我发现了一个非常有用的包,名为,它允许您以更自然的方式实现代码重用。不使用可重用表达式,而是使用常规OOP可重用原语,如computed get only属性和instance/static/extension方法,并简单地用[Decompile]属性标记它们。e、 g.在某些公共静态类中:

[反编译] public static bool earnsmorethanparenthis Child,Parent Parent=>Child.Salary>Parent.Salary; 或者在儿童班:

[反编译] public bool earnsMorthanParentParent=>this.Salary>parent.Salary; 然后,您只需在查询的某个点调用反编译自定义扩展方法:

return\u context.Set .Whereparent=>parent.Children.Anychild=> child.earnsmorethan父母 .反编译; 这看起来比使用表达式要好得多。缺点与其他解决方案相同——需要为每个查询调用自定义方法。在我对的回答中,我展示了一个将包插入EF Core 3.1查询处理管道的解决方案,我希望在未来EF Core中有类似的公共扩展点,它将消除那里需要的大量样板代码,这将提供最好的使用OOP功能,在表达式树和转换扩展中,替换为实际表达式,使其透明。e、 g.如前所述,插入DelegateDecompiler后,查询与为LINQ to对象编写的查询一样简单:

return\u context.Set .Whereparent=>parent.Children.Anychild=> child.earnsmorethan父母;
谢谢-那很有帮助。我希望能够将我的表达式分成小的单元,其中一些被其他人调用,但我开始明白,这比看起来更困难,原因正如你所解释的。是的,它仍然需要从顶部对象开始,在这种情况下,它是父对象。您也可以使用PredicateBuilder或类似的组合,并编写_context.Set.whereEarnsMorethan parent.AndSomeOtherCondition.nototherCondition;但是所有这些条件仍然应该基于父对象谢谢-这非常有用。我希望能够将我的表达式分成小的单元,其中一些被其他人调用,但我开始明白,这比看起来更困难,原因正如你所解释的。是的,它仍然需要从顶部对象开始,在这种情况下,它是父对象。您也可以使用PredicateBuilder或类似的组合,并编写_context.Set.whereEarnsMorethan parent.AndSomeOtherCondition.nototherCondition;但所有这些条件仍然应基于父对象。谢谢您的发布!这看起来是一个非常强大的概念,我很高兴尝试一下。谢谢你的帖子!这看起来是一个非常强大的概念,我很高兴尝试一下。