4
\$\begingroup\$

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;
}
\$\endgroup\$
1
\$\begingroup\$

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))
}
\$\endgroup\$
1
\$\begingroup\$

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;

}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.