在linq select语句中使用func选择匿名类型的值

时间:2012-07-23 21:48:42

标签: c# linq entity-framework

我有一个泛型类型Filter,它使用一些lambda表达式从类型中选择值,以便该类可重用。该类用于另一个泛型类Search,它将使用Filter来选择最终将在下拉列表中使用的不同类型的项。

我删除了这些不重要的代码。

public class Filter<T>
{
   public string Name;
   public Func<T, string> Key;
   public Func<T, string> Value;
}

public class Search<T>
{
   MyDBContext db = new MyDBContext();
   IQueryable<T> Model = db.Stuff.OrderBy(a => a.TermID);
   Filter filter = new Filter(
      Name: "Term",
      Value: a => a.TermID.ToString(),
      Key: a => a.Term.TermType.Name
   );

   var filterItems = Model
      .Select(a => new { Key = filter.Key(a), Value = filter.Value(a)})
      .OrderBy(t => t.Key)
      .Distinct()
      .ToArray();
}

我收到了运行时错误:The LINQ expression node type 'Invoke' is not supported in LINQ to Entities. 我尝试过使用强类型而不是匿名类型,并在Filter中使用Expression<Func<T,string>>

经过几个小时的搜索和尝试不同的事情,我不知道如何使这项工作。 谢谢你的帮助。

1 个答案:

答案 0 :(得分:0)

你的问题可以更简单地表达出来,例如,这再现了它:

Func<SomeClass, int> x = t => t.ID;
var y = db.SomeClasses.Select(c => x(c)).ToArray();

它编译得很好,但在运行时会出现相同的错误,因为您正在调用编译的函数。那部分“t =&gt; t.ID”是编译代码(至少是IL),linq无法读取它以将其转换为SQL。它只能将表达式树转换为SQL。上述案例的解决方案相当简单,我不确定这将如何转化为您的情况,但它应该是可能的。

Expression<Func<SomeClass, int>> x = t => t.ID;
var y = db.SomeClasses.Select(x).ToArray();

还可以选择将函数调用移动到linq到对象,这样就不需要将它转换为sql(在客户端处理“AsEnumerable”之后的所有内容)。这样可以在函数中放置更大的灵活性,并消除您所获得的错误类型。这也将消除对SqlFunctions调用的需要(见下文)。缺点是可能会返回比服务器更多的行。

Func<SomeClass, int> x = t => t.ID;
var y = db.SomeClasses.AsEnumerable().Select(c => x(c)).ToArray();

你的最后一个问题是EF不喜欢ToString方法,你需要使用SqlFunctions.StringConvert这很糟糕。见这里:int to string in Entity Framework