Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/319.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
C# 在EF中使用表达式返回方法_C#_Entity Framework - Fatal编程技术网

C# 在EF中使用表达式返回方法

C# 在EF中使用表达式返回方法,c#,entity-framework,C#,Entity Framework,我有一个表达式返回方法,例如: public Expression<Func<User, bool>> GetUserPredicate(int userID) { return u => u.ID == userID; } 但我也希望在查询其他实体(如帖子)时使用它: var post = dbContext.Posts .Where(p => p.ID == 1) .Wher

我有一个表达式返回方法,例如:

    public Expression<Func<User, bool>> GetUserPredicate(int userID)
    {
        return u => u.ID == userID;
    }
但我也希望在查询其他实体(如帖子)时使用它:

    var post = dbContext.Posts
        .Where(p => p.ID == 1)
        .Where(p.User => GetUserPredicate(1))
        .Single();

但这是行不通的。如何实现它?

您可以创建一个通用方法。问题是您需要访问不相关类的属性。但这在泛型中是不可能的,除非泛型类型约束使这些属性可用。想法:在接口中定义所需的属性:

public interface IUserProvider
{
    int UserID { get; set; }
}

public class User : IUserProvider ...
public class Post : IUserProvider ...
然后将该方法定义为

public Expression<Func<TEntity, bool>> GetUserPredicate<TEntity>(int userID)
    where TEntity : IUserProvider
{
    return e => e.UserID == userID;
}
公共表达式GetUserPredicate(int-userID)
地点:IUserProvider
{
返回e=>e.UserID==UserID;
}
编辑:
我的解决方案使用表达式的编译函数。由于EF只查看表达式树并将其转换为Sql,因此它无法处理已编译函数,因为这些函数不是表达式树(请参见下面Filip Corades的评论)。
如果您将我的代码用于其他可以使用编译函数的事情,那么您不应该有任何问题。然而,对于这个问题,这不是正确的答案

原始答案:

您可以添加另一个使用第一个方法的方法

public Expression<Func<Post, bool>> GetPostUserPredicate(int userID)
{
    Expression<Func<User, bool>> expr = GetUserPredicate(userID);
    Func<User, bool> func = expr.Compile();
    return post => func(post.User);
}
您也可以将其内联,而不是使用额外的函数,但对我来说,这有点太乱了。我还是要加上:

var post = dbContext.Posts
    .Where(p => p.ID == 1)
    .Where(p => GetUserPredicate(1).Compile()(p.User))
    .Single();
如果在编译表达式方面我没有遗漏什么,那么这应该可以很好地工作。

希望这有帮助,并让我知道它是否有效。

编译器说了什么?@CodeNotFound p在上下文中不存在。您应该使用
。Where(p=>GetUserPredicate(1)
而不是
。Where(p.User=>GetUserPredicate(1))
标记为“重复”的问题的答案允许您从
Expression
Expression
合成
Expression
。另请参阅和类似内容,它们更一般地解释并尝试解决表达式合成问题。LinqKit提供自定义扩展方法
Invoke
,该方法与
AsExpandable()一起工作因此用法是
var userPredicate=GetUserPredicate(1);var post=dbContext.Posts.AsExpandable.Where(p=>userPredicate.Invoke(p.User)
.Nether C#或BCL提供了这种开箱即用的功能。但Post没有用户ID属性,它有一个用户导航属性,该属性具有ID属性。这与其他实体相同。
GetUserPredicate
总是返回相同的谓词,并且必须对可比较的属性进行操作,或者使用两个不同的m方法
GetUserPredicateFromUser
GetUserPredicateFromPost
。为什么不添加一个
UserID
?您可以使用EF拥有一个导航属性+外键。编译后的函数不会转换为sql。@FilipCordas真的吗?我担心可能会出现类似的情况。我不会删除它,除非我有一个nswer从OP查看它是否有效(我显然没有确切的设置)。它说“LINQ to实体中不支持LINQ表达式节点类型‘Invoke’。”(难道没有其他方法可以让它工作吗?没有什么Ef它需要c#表达式树并将其转换为Sql,因为编译后的函数不是表达式树,所以无法获得原始函数。@FilipCordas我想不知何故,表达式应该在不调用编译的情况下进行转换(转换)?
var post = dbContext.Posts
        .Where(p => p.ID == 1)
        .Where(GetPostUserPredicate(1))
        .Single();
var post = dbContext.Posts
    .Where(p => p.ID == 1)
    .Where(p => GetUserPredicate(1).Compile()(p.User))
    .Single();