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

时间:2019-06-01 15:11:31

标签: c# entity-framework

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

    public Expression<Func<User, bool>> GetUserPredicate(int userID)
    {
        return u => u.ID == userID;
    }

(在原始代码中,这是我想重用的更长,更复杂的逻辑,以便将其提取出来成为这种方法。)

我可以毫无疑问地在用户查询中使用它:

    var user = dbContext.Users
        .Where(GetUserPredicate(1))
        .Single();

但是我也想在查询其他实体(例如帖子)时使用它:

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

但这不起作用。如何实现?

3 个答案:

答案 0 :(得分:0)

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

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;
}

答案 1 :(得分:0)

修改:
我的解决方案使用表达式的编译函数。由于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(GetPostUserPredicate(1))
        .Single();

您也可以内联而不是使用额外的函数,但是对我来说这有点太混乱了。无论如何,我都会添加它:

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

如果我对编译表达式没有什么遗漏,这应该可以正常工作。
希望这会有所帮助,让我知道它是否有效。

答案 2 :(得分:-2)

也许可以,

public Expression<Func<Object, bool>> GetUserPredicate(int userID)
{

}

否则,如果没有与发布相关的用户标识,则您需要一种新方法。