将LINQ子查询移动到扩展方法会在运行时失败

时间:2016-03-28 16:48:42

标签: c# linq

我在LINQPad中编写了这个LINQ查询。我正在做这样的事情:

var perms = (from x in db.TableName // etc
            select new ProfilePermission
            { // etc
            });

perms = perms.Concat(from x in db.TableName // etc
            select new ProfilePermission
            { // etc
            });

var results = (from pi in db.AnotherTable
                where pi.IsActive
                select new MyViewModel
                {
                    KeyId = pi.Id,
                    Permissions = (from pm in perms
                                    where pi.ChildId == pm.ChildId
                                    select pm)
                }

使用此子查询有效。所以,我想,让我们把它转移到扩展方法。我试过这样做:

public static IQueryable<ProfilePermission> GetProfilePermissions
    (
    this IMkpContext db
    )
{
    var perms = (from x in db.TableName // etc
            select new ProfilePermission
            { // etc
            });

    perms = perms.Concat(from x in db.TableName // etc
            select new ProfilePermission
            { // etc
            });


    return perms;
}

var results = (from pi in db.AnotherTable
                where pi.IsActive
                select new MyViewModel
                {
                    KeyId = pi.Id,
                    Permissions = (from pm in db.GetProfilePermissions()
                                    where pi.ChildId == pm.ChildId
                                    select pm)
                }

现在我收到一条消息:

  

NotSupportedException:LINQ to Entities无法识别方法&#39; System.Linq.IQueryable`1 [PublicationSystem.Model.ViewModels.ProfilePermission] GetProfilePermissions(PublicationSystem.Model.IMkpContext)&#39;方法,并且此方法无法转换为商店表达式。

为什么子查询以一种方式工作,而不是另一种方式?我认为这两种方式最终都是IQueryable<>

1 个答案:

答案 0 :(得分:3)

不同之处在于,在您使用扩展方法的地方,它没有被执行,而是成为另一个表达式的一部分(在您的情况下为Select),即被记忆为MethodCallExpression到EF查询提供程序无法识别的方法。

如果您确实在某些顶级查询构造中使用了扩展方法,例如JoinGroupJoin,则可以使用。或者,如果您可以在查询之外移动调用并将结果存储到变量中。

例如,在您的情况下,以下内容将起作用:

var results = 
    from pi in db.AnotherTable
    where pi.IsActive
    join pm in db.GetProfilePermissions() on pi.ChildId equals pm.ChildId into permissions
    select new MyViewModel
    {
        KeyId = pi.Id,
        Permissions = permissions
    };

以及:

var permissions = db.GetProfilePermissions();
var results =
    from pi in db.AnotherTable
    where pi.IsActive
    select new MyViewModel
    {
        KeyId = pi.Id,
        Permissions = (from pm in permissions
                        where pi.ChildId == pm.ChildId
                        select pm)
    };