问题
I'm trying to build a query that will execute against the database as an IQueryable, and not in memory (IEnumerable).
The query will be used for several different purposes and each purpose has a slightly different way in which the Total property is calculated.
Because I'm using a Func for calculating the total, i get an error advising me that sql doesn't know how to deal with the Invoke method of my Func, which is understandable.
To get past the problem, i have had to list the groupings into memor by calling ToList() which is not good for performance.
Is there a way that i can execute this query as an IQueryable? Otherwise im going to have to write this query 20+ times with a calculation variance
Func<IGrouping<object, MyType>, double?> calculateTotal= (group) => @group.Sum(x => x.PassengerTotal);
Dictionary<object, double?> weekValues = queryable.GroupBy(o => new
{
Year = SqlFunctions.DatePart("yyyy", o.DateCreated),
Week = SqlFunctions.DatePart("ww", o.DateCreated),
Source = o.SourceId,
})
.ToList() //NEED TO REMOVE THIS CALL
.Select(ac => new WeeklyGraphGroup()
{
Year = ac.Key.Year,
Week = ac.Key.Week,
SourceId = ac.Key.Source,
Total = calculateTotal(ac)
})
.ToDictionary(dict =>
new
{
Year = dict.Year,
Week = dict.Week,
Source = dict.SourceId
}, grp => grp.Total);
回答1:
Create a partial class as follows:
public partial class WeeklyGraphGroup
{
public int ? Year { get; set; }
public int ? Week { get; set; }
public int Source { get; set; }
}
public partial class WeeklyGraphGroup
{
private int ? _Total;
public int ? Total
{
get
{
this._Total = CalculateTotal(this.Year, this.Week, this.Source);
return this._Total;
}
}
public int ? CalculateTotal(int ? Year, int ? Week, int Source)
{
// do your calculation and return the value of total
// use whatever formula you want here. I guess you are calculating
// total based on any of the parameters(year, week or source);
return value;
}
}
Then do your query as below:
var list = db.Stores.GroupBy(o => new WeeklyGraphGroup
{
Year = SqlFunctions.DatePart("yyyy", o.DateCreated),
Week = SqlFunctions.DatePart("ww", o.DateCreated),
Source = o.SourceId,
})
.Select ( u => new WeeklyGraphGroup
{
Year = u.Key.Year,
Week = u.Key.Week,
Source = u.Key.Source
}
).ToList();
Total will be updated automatically
来源:https://stackoverflow.com/questions/42067722/use-a-c-sharp-func-as-part-of-an-iqueryable-without-executing-into-memory-call