C# 在linq Select语句中使用func选择匿名类型中的值
我有一个泛型类型类过滤器,它使用一些lambda表达式从类型中选择值,以便该类是可重用的。该类在另一个泛型类型类搜索中使用,该类将使用筛选器选择最终将在下拉列表中使用的类型的不同项 我删除了这些不重要的代码C# 在linq Select语句中使用func选择匿名类型中的值,c#,linq,entity-framework,C#,Linq,Entity Framework,我有一个泛型类型类过滤器,它使用一些lambda表达式从类型中选择值,以便该类是可重用的。该类在另一个泛型类型类搜索中使用,该类将使用筛选器选择最终将在下拉列表中使用的类型的不同项 我删除了这些不重要的代码 public class Filter<T> { public string Name; public Func<T, string> Key; public Func<T, string> Value; } public class
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();
}
公共类过滤器
{
公共字符串名称;
公钥;
公共职能价值;
}
公共类搜索
{
MyDBContext db=新的MyDBContext();
IQueryable Model=db.Stuff.OrderBy(a=>a.TermID);
过滤器=新过滤器(
名称:“期限”,
值:a=>a.TermID.ToString(),
Key:a=>a.Term.TermType.Name
);
var filterItems=模型
.Select(a=>new{Key=filter.Key(a),Value=filter.Value(a)})
.OrderBy(t=>t.Key)
.Distinct()
.ToArray();
}
我得到运行时错误:LINQ to实体中不支持LINQ表达式节点类型“Invoke”。
我尝试过使用强类型而不是匿名类型,并在过滤器中使用Expression
经过数小时的搜索和尝试,我不知道如何使这项工作。
谢谢您的帮助。您的问题可以更简单地表达出来,例如,这再现了它:
Func<SomeClass, int> x = t => t.ID;
var y = db.SomeClasses.Select(c => x(c)).ToArray();
Func x=t=>t.ID;
vary=db.SomeClasses.Select(c=>x(c)).ToArray();
它可以很好地编译,但在运行时会出现相同的错误,因为您正在调用已编译的函数。部分“t=>t.ID”是编译代码(至少到IL),linq无法读取该部分以将其转换为SQL。它只能将表达式树转换为SQL。上述情况的解决方案相当简单,我不确定这将如何转化为您的情况,但这应该是可能的
Expression<Func<SomeClass, int>> x = t => t.ID;
var y = db.SomeClasses.Select(x).ToArray();
表达式x=t=>t.ID;
var y=db.SomeClasses.Select(x.ToArray();
还可以选择将函数调用移动到linq to对象中,这样就不需要将其转换为sql(在客户端上处理“AsEnumerable”之后的所有内容)。这允许在函数中放置更大的灵活性,并将消除您所遇到的错误类型。这也将消除调用SqlFunctions的需要(见下文)。缺点是从服务器返回的行可能比需要的多
Func<SomeClass, int> x = t => t.ID;
var y = db.SomeClasses.AsEnumerable().Select(c => x(c)).ToArray();
Func x=t=>t.ID;
var y=db.SomeClasses.AsEnumerable().Select(c=>x(c)).ToArray();
最后一个问题是EF不喜欢ToString方法,您需要使用SqlFunctions.StringConvert,这相当糟糕。请参见此处:您的问题可以更简单地表达出来,例如,这再现了它:
Func<SomeClass, int> x = t => t.ID;
var y = db.SomeClasses.Select(c => x(c)).ToArray();
Func x=t=>t.ID;
vary=db.SomeClasses.Select(c=>x(c)).ToArray();
它可以很好地编译,但在运行时会出现相同的错误,因为您正在调用已编译的函数。部分“t=>t.ID”是编译代码(至少到IL),linq无法读取该部分以将其转换为SQL。它只能将表达式树转换为SQL。上述情况的解决方案相当简单,我不确定这将如何转化为您的情况,但这应该是可能的
Expression<Func<SomeClass, int>> x = t => t.ID;
var y = db.SomeClasses.Select(x).ToArray();
表达式x=t=>t.ID;
var y=db.SomeClasses.Select(x.ToArray();
还可以选择将函数调用移动到linq to对象中,这样就不需要将其转换为sql(在客户端上处理“AsEnumerable”之后的所有内容)。这允许在函数中放置更大的灵活性,并将消除您所遇到的错误类型。这也将消除调用SqlFunctions的需要(见下文)。缺点是从服务器返回的行可能比需要的多
Func<SomeClass, int> x = t => t.ID;
var y = db.SomeClasses.AsEnumerable().Select(c => x(c)).ToArray();
Func x=t=>t.ID;
var y=db.SomeClasses.AsEnumerable().Select(c=>x(c)).ToArray();
最后一个问题是EF不喜欢ToString方法,您需要使用SqlFunctions.StringConvert,这相当糟糕。请参见此处:我怀疑任何
过滤器。Key
和过滤器。Value
do都可以从LINQ转换到后端存储。如果调用是主要问题,则可以通过使用ExpressionVisitor融合这两个表达式来避免。我不在电脑前,但如果你没有得到任何乐趣,请提醒我,我将添加一个示例。我怀疑filter.Key
和filter.Value
所做的任何事情都可能从LINQ转换到后端存储。如果调用是主要问题,则可以使用ExpressionVisitor将这两个表达式进行融合来避免。我不在电脑前,但如果你没有得到任何乐趣,提醒我,我会添加一个例子。