尝试使用Expression <func <..>&gt;调用Any()时输入错误从方法

时间:2016-11-13 06:26:08

标签: c# entity-framework linq iqueryable

我正在从我的EF实体创建一个可重用的映射表达式到我的BLL实体:

private Expression<Func<Person, bool>> GetNameFilter(string name)
{
    return person => person.Profile.UserName == name;
}

internal Expression<Func<Ef.Perk, Bll.Perk>> MapPerkPerk(string name)
{
    return perk => new Bll.Perk
        {
            Id = perk.PerkId,
            Name = perk.PerkName,
            Description = perk.PerkDescription,

            //Compilation Error
            Owned = perk.Players.Any(GetNameFilter(name)) 
        };
}

我在注意到的行上遇到了编译错误。错误如下:

  

ICollection不包含&#39;任何&#39;的定义。和最好的扩展方法重载&#39; Queryable.Any(IQueryable,Expression&gt;)&#39;需要一个类型为“IQueryable&#39;

的接收器

但是当我直接推送这个表达式时,这不会发生:

internal Expression<Func<Ef.Perk, Bll.Perk>> MapPerkPerk(string name)
{
    return perk => new Bll.Perk
        {
            Id = perk.PerkId,
            Name = perk.PerkName,
            Description = perk.PerkDescription,

            //No Compilation Error
            Owned = perk.Players.Any(person => person.Profile.UserName == name)
        };
}

为什么会这样?两个表达式的类型是相同的。

使用下面找到的LinqExpression解决方案,我现在在运行时收到以下错误:

  

类型&#39; System.InvalidCastException&#39;的例外情况发生在LinqKit.dll但未在用户代码中处理

     

附加信息:无法转换类型为&System; Linin.Expressions.InstanceMethodCallExpressionN&#39;的对象。输入&#39; System.Linq.Expressions.LambdaExpression&#39;。

internal FutureQuery<Perk> GetPlayerInfoPerks(string username)
{
    return Master
            .Perks
            .VisiblePerks
            .Select(Master.Perks.MapPerkPerk(username))
            .Future();
}

这是由于使用了EntityFramework.Future库吗?

1 个答案:

答案 0 :(得分:1)

  

为什么会这样?两个表达式的类型是相同的。

两个表达式的类型 相同 - 它们看起来只是视觉上相同。以下是有效的:

dbContext.Persons.Any(GetNameFilter(name))

而这不是:

perk.Players.Any(GetNameFilter(name))

为什么呢?因为第一个需要Expression<Func<...>>而第二个只需Func<..>IQueryable<T>IEnumerable<T>方法之间的典型差异具有相同的名称)。希望你看到差异。当你直接输入它时,C#编译器会发出它的魔力来发出一个或另一个,但是当你手动执行它时,你应该使用正确的。

问题由LinqKit包与Invoke / Expand自定义扩展方法(更常见的是AsExpandable)解决。

对于您的具体示例,LinqKit解决方案可能是这样的:

using LinqKit;

...

internal Expression<Func<Ef.Perk, Bll.Perk>> MapPerkPerk(string name)
{
    // LinqKit requires expressions to be in variables
    var nameFilter = GetNameFilter(name);
    return Linq.Expr((Ef.Perk perk) => new Bll.Perk
    {
        Id = perk.PerkId,
        Name = perk.PerkName,
        Description = perk.PerkDescription,
        Owned = perk.Players.Any(p => nameFilter.Invoke(p)) 
    }).Expand();
}