我在Linq中有一个查询需要根据用户在表单中选择的某些值进行动态调整。我的查询如下:
(from data in DbContext.CoacheeData
group data by data.UserId into g
select new LeaderboardEntry
{
Name = g.FirstOrDefault().UserName,
Value = g.Sum(data => data.Steps),
});
我希望此查询的两个方面是动态的:
我一直在尝试 - 并且失败 - 为此使用Linq表达式,但我不断收到运行时错误。我在Linq很新,所以我可能做了些蠢事。
以下是CoacheeData类的摘录。如果有帮助,所有属性都是数字。除了步骤之外,所有浮动都是均匀的。
public class CoacheeData
{
[Key]
public long Id { get; set; }
[Required]
[ForeignKey("User")]
public string UserId { get; set; }
public virtual ApplicationUser User { get; set; }
public DateTime Date { get; set; }
//Each of these properties should be selectable by the query
public int Steps { get; set; }
public float Distance { get; set; }
public float CaloriesBurned { get; set; }
//...etc
}
Func<CoacheeData, int> testLambda = (x) => x.Steps;
//Used inside the query like this:
Value = g.Sum(testLambda),
这会引发异常(&#34;内部.NET Framework数据提供程序错误1025。&#34;),我认为这是正常的,因为您无法在Linq to SQL中直接使用lambda 。如果我错了,请纠正我。所以我尝试了一个表达式:
Expression<Func<CoacheeData, int>> varSelectExpression = (x) => x.Steps;
//And in the query:
Value = g.Sum(varSelectExpression.Compile()),
抛出相同的错误1025,这是按预期工作的,因为Compile()调用再次将表达式更改为lambda,在我的理解中。但是我不能省略Compile()调用,因为Linq代码没有编译。不知道如何解决这个问题。
我尝试了类似的事情,我怀疑我的错误(和解决方案)将具有可比性。如果需要,我稍后会添加更多信息。
答案 0 :(得分:0)
您可以使用DynamicLINQ库。这些允许您使用字符串构造查询。以下是一些链接(其中一些可能是彼此的扩展 - 每个链接看起来都不太多。)
https://www.nuget.org/packages/System.Linq.Dynamic/
http://weblogs.asp.net/scottgu/dynamic-linq-part-1-using-the-linq-dynamic-query-library
答案 1 :(得分:0)
类型安全的解决方案是动态构建result.AsyncState
表达式。我的组件AdaptiveLINQ就是为此而设计的。
它在LINQ查询中引入了 cube 的概念。
只需定义一个具有1个动态维度和1个动态度量的多维数据集。
GroupBy
并使用class MyCubeItem
{
public string Name { get; set; }
public double Value { get; set; }
}
class MyCube : ICubeDefinition<CoacheeData, MyCubeItem>
{
public string DimensionName { get; set; }
public string AggregateName { get; set; }
public string AggregateOperator { get; set; }
public Expression<Func<CoacheeData, string> Name
{
get
{
switch (DimensionName)
{
case "UserId":
return x => x.UserId;
...
}
}
}
public Expression<Func<CoacheeData, string> Value
{
get
{
switch (AggregateName)
{
case "Steps":
switch (AggregateOperator)
{
case "Sum":
return items => items.Sum(x => x.Steps);
...
}
}
}
}
}
LINQ扩展方法:
QueryByCube
答案 2 :(得分:0)
你几乎拥有它。为此,您只需在传入表达式时使用扩展方法。 EF的linq to sql不支持将表达式传递给表达式。
请注意,如果其中一种数值数据类型,则以下方法效果最佳。我正在使用float
;
var baseQ = (from data in DbContext.CoacheeData
group data by data.UserId into g
select g);
Expression<Func<CoacheeData,float> expression;
switch(propName){
case "Distance":
expression = x=> x.Distance; break;
case "CaloriesBurned":
expression = x=>x.CaloriesBurned; break;
}
switch(aggregateFn) {
case AggregateFn.Sum:
return baseQ.Sum(expression);
case AggregateFn.Max:
return baseQ.Max(expression);
//...
}
AggregateFn
是此示例中的枚举。