在Queryable上获取下一个和上一个

时间:2015-04-21 07:04:57

标签: c# linq

哟什么匪帮?

我有以下代码似乎总是返回null

    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);
        }
    }

给定来自数据源的Queryable及其中的记录,我只想获取下一个和之前的值。

2 个答案:

答案 0 :(得分:4)

原因是EntityFramework不支持SkipWhile

首先,要使用SkipTake,集合必须是一些才能使EntityFramework支持该方法。 因此,在方法调用之前,您需要使用OrderBy方法:

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

然后你的下一个方法可能是这样的:

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
}

该方法有一个缺点。它不是通用。但只需付出一点努力,您就可以准备一个通用版本:

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
}

如果您不喜欢字符串作为名称:

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

用法:

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

可在codeplex

上找到 System.Linq.Dynamic 的通用版本继电器

我希望它能为您提供一些线索,让您了解如何使您的代码工作,或者知道如何使用其他方法实现它。

答案 1 :(得分:1)

也许我会因为这个解决方案而被钉死在十字架上(因为我发现它有点脏)......但是......它有效(并且它没有使用TakeWhile或SkipWhile或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);
    }
}