Since Entity Set does not support asqueryable, I have to do this. How can I reduce the amount of redundant code between the two methods?
public static IQueryable<T> WhereCreateWithin<T>(this IQueryable<T> query, DateManager.TimeRange timeRange, DateTime? beginDayParam = null) where T : IHasCreateDate
{
if (beginDayParam == null)
{
beginDayParam = DateTime.Today;
}
DateTime beginDay = beginDayParam.Value.Date;
DateTime startRange;
DateTime endRange;
switch (timeRange)
{
case DateManager.TimeRange.All:
return query;
case DateManager.TimeRange.ThisYear:
startRange = new DateTime(beginDay.Year, 1, 1); // January 1, this year
endRange = startRange.AddYears(1);
return query.Where(p => p.create_date.Date >= startRange && p.create_date < endRange);
case DateManager.TimeRange.ThisMonth:
startRange = new DateTime(beginDay.Year, beginDay.Month, 1);
endRange = startRange.AddMonths(1).Date;
return query.Where(p => p.create_date.Date >= startRange && p.create_date < endRange);
case DateManager.TimeRange.ThisWeek:
startRange = BuilkHelper.DateHelper.StartOfWeek(beginDay, DayOfWeek.Monday);
endRange = startRange.AddDays(6);
return query.Where(p => p.create_date.Date >= startRange && p.create_date < endRange);
case DateManager.TimeRange.ToDay:
return query.Where(p => p.create_date.Date == beginDay);
case DateManager.TimeRange.Last30Day:
startRange = beginDay.AddDays(-29);
endRange = beginDay;
return query.Where(p => p.create_date.Date >= startRange && p.create_date <= endRange);
}
return query;
}
public static IEnumerable<T> WhereCreateWithin<T>(this IEnumerable<T> query, DateManager.TimeRange timeRange, DateTime? beginDayParam = null) where T : IHasCreateDate
{
if (beginDayParam == null)
{
beginDayParam = DateTime.Today;
}
DateTime beginDay = beginDayParam.Value.Date;
DateTime startRange;
DateTime endRange;
switch (timeRange)
{
case DateManager.TimeRange.All:
return query;
case DateManager.TimeRange.ThisYear:
startRange = new DateTime(beginDay.Year, 1, 1); // January 1, this year
endRange = startRange.AddYears(1);
return query.Where(p => p.create_date.Date >= startRange && p.create_date < endRange);
case DateManager.TimeRange.ThisMonth:
startRange = new DateTime(beginDay.Year, beginDay.Month, 1);
endRange = startRange.AddMonths(1).Date;
return query.Where(p => p.create_date.Date >= startRange && p.create_date < endRange);
case DateManager.TimeRange.ThisWeek:
startRange = BuilkHelper.DateHelper.StartOfWeek(beginDay, DayOfWeek.Monday);
endRange = startRange.AddDays(6);
return query.Where(p => p.create_date.Date >= startRange && p.create_date < endRange);
case DateManager.TimeRange.ToDay:
return query.Where(p => p.create_date.Date == beginDay);
case DateManager.TimeRange.Last30Day:
startRange = beginDay.AddDays(-29);
endRange = beginDay;
return query.Where(p => p.create_date.Date >= startRange && p.create_date <= endRange);
}
return query;
}
2 Answers 2
Given that the logic is exactly the same (i did not do a line by line comparision), one of the possible solutions whould be:
private static TCollection WhereCreateWithin<T, TCollection>(TCollection query,
DateManager.TimeRange timeRange,
DateTime? beginDayParam,
Func<TCollection, Func<T, bool>, TCollection> selector)
where T : IHasCreateDate
where TCollection : IEnumerable<T>
{
//insert your logic here
//replace query.Where(x => ... ) call with selector(query, x => ... ) call
}
public static public static IQueryable<T> WhereCreateWithin<T>(this IQueryable<T> query, DateManager.TimeRange timeRange, DateTime? beginDayParam = null) where T : IHasCreateDate
{
return WhereCreateWithin<T, IQueryable<T>>(query, timeRange, beginDayParam, (q, f) => q.Where(x => f(x)))
}
public static public static IEnumerable<T> WhereCreateWithin<T>(this IEnumerable<T> query, DateManager.TimeRange timeRange, DateTime? beginDayParam = null) where T : IHasCreateDate
{
return WhereCreateWithin<T, IEnumerable<T>>(query, timeRange, beginDayParam, (q, f) => q.Where(f))
}
The IQueryable Where extension method takes an Expression whereas the IEnumerable Where extension method takes a normal delegate (Func). Any solution to consolidate the OPs code will have to take this into account. It is easy to convert an expression to a delegate by calling Compile on the expression (but hard the other way around) therefore I have based the below solution on the first principle.
public static IEnumerable<T> WhereCreateWithin<T>(this IEnumerable<T> query, DateManager.TimeRange timeRange, DateTime? beginDayParam = null) where T : IHasCreateDate
{
return WhereCreateWithin<IEnumerable<T>, T>(query, timeRange, (q, ex) => q.Where(ex.Compile()), beginDayParam);
}
public static IQueryable<T> WhereCreateWithin<T>(this IQueryable<T> query, DateManager.TimeRange timeRange, DateTime? beginDayParam = null) where T : IHasCreateDate
{
return WhereCreateWithin<IQueryable<T>, T>(query, timeRange, (q, ex) => q.Where(ex), beginDayParam);
}
public static TColl WhereCreateWithin<TColl, T>(this TColl toBeFiltered,
DateManager.TimeRange timeRange,
Func<TColl, Expression<Func<T, bool>>, TColl> getFilteredCollection,
DateTime? beginDayParam = null) where T : IHasCreateDate
where TColl : IEnumerable<T>
{
if (beginDayParam == null)
{
beginDayParam = DateTime.Today;
}
DateTime beginDay = beginDayParam.Value.Date;
var expressionDictionary = new Dictionary<DateManager.TimeRange, Expression<Func<T, bool>>>();
expressionDictionary.Add(DateManager.TimeRange.ThisYear, p => p.create_date.Date >= new DateTime(beginDay.Year, 1, 1) && p.create_date < new DateTime(beginDay.Year, 1, 1).AddYears(1));
expressionDictionary.Add(DateManager.TimeRange.ThisMonth, p => p.create_date.Date >= new DateTime(beginDay.Year, beginDay.Month, 1) && p.create_date < new DateTime(beginDay.Year, beginDay.Month, 1).AddMonths(1).Date);
expressionDictionary.Add(DateManager.TimeRange.ThisWeek, p => p.create_date.Date >= BuilkHelper.DateHelper.StartOfWeek(beginDay, DayOfWeek.Monday) && p.create_date < BuilkHelper.DateHelper.StartOfWeek(beginDay, DayOfWeek.Monday).AddDays(6));
expressionDictionary.Add(DateManager.TimeRange.ToDay, p => p.create_date.Date == beginDay);
expressionDictionary.Add(DateManager.TimeRange.Last30Day, p => p.create_date.Date >= beginDay.AddDays(-29) && p.create_date <= beginDay);
return expressionDictionary.ContainsKey(timeRange) ? getFilteredCollection(toBeFiltered, expressionDictionary[timeRange]) : toBeFiltered;
}