Getting next and previous in Queryable

What kind of gangsters?

I have the following code that seems to null

always return .

    public static T GetNext<T>(this IQueryable<T> list, T current)
    {
        try
        {
            return list.SkipWhile(x => !x.Equals(current)).Skip(1).First();
        }
        catch
        {
            return default(T);
        }
    }

    public static T GetPrevious<T>(this IQueryable<T> list, T current)
    {
        try
        {
            return list.TakeWhile(x => !x.Equals(current)).Last();
        }
        catch
        {
            return default(T);
        }
    }

      

Given a Queryable from a data source and a record in it, I just want to get the next and previous values.

+3


source to share


2 answers


The reason is that SkipWhile

EntityFramework is not supported.

First, to use, Skip

or the Take

collection needs to be some kind to get the EntityFramework to support these methods. Thus, before calling the method, you need to have a method OrderBy

:

 var orderedList = list.OrderBy(elem => elem.Id) // or other property 
                                                // but need to be rememebered
                                                // because it will be used in furher

      

Then your method for the following could be:

public static T GetNext<SomeEntity>(
            this IOrderedQueryable<SomeEntity> list,
            SomeEntity current)
{
    return list.Where(elem => elem.Id > current.Id)
               .FirstOrDefault(); // faster than try-catch
     // assuming, that Id is unique
}

      

This method has one drawback. It's not common . But with a little effort, you can prepare a generic version:

public static T GetNext<T>(this IOrderedQueryable<T> list, T current, string orderProperty)
{
    var predicate = string.Format("{0} > @0", orderProperty);
    var propValue = current.GetType()
                           .GetProperty(orderProperty, 
                                        BindingFlags.Public | BindingFlags.Instance)
                           .GetValue(current);
    return (T)list.Where(predicate, propValue).FirstOrDefault();
                  //where comes from System.Linq.Dynamic
}

      



If you don't like strings as rights names:

public static T GetNext<T>(this IOrderedQueryable<T> list, 
                          T current, 
                          Func<T, object> orderProperty)
{
    ..
    var propValue = orderProperty(current);
    ..
}

      

And usage:

orderedList.GetNext(current, orderProperty: elem => elem.Id);

      

The generic version supports the System.Linq.Dynamic relay which can be found at codeplex

Hopefully this will give you some insight on how to get your code to work or some insight on how to implement it with a different approach.

+4


source


Maybe I'm crucified for this solution (because I find it messy) ... but ... it works (and it doesn't use TakeWhile or SkipWhile or DynamicLINQ):



public static T GetNext<T>(this IQueryable<T> list, T current)
{
    try
    {
        int idx = 0;
        foreach (T item in list)
        {
            if (!item.Equals(current))
            {
                idx++;
            }
            else
            {
                break;
            }
        }

        return list.Skip(idx).First();
    }
    catch
    {
        return default(T);
    }
}

public static T GetPrevious<T>(this IQueryable<T> list, T current)
{
    try
    {
        int idx = 0;
        foreach (T item in list)
        {
            if (!item.Equals(current))
            {
                idx++;
            }
            else
            {
                break;
            }
        }
        if (idx - 1 == 0)
            return list.First();
        return list.Skip(idx - 1).First();
    }
    catch
    {
        return default(T);
    }
}

      

+1


source







All Articles