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.
source to share
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.
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);
}
}
source to share