【问题标题】:Getting next and previous on a Queryable在 Queryable 上获取下一个和上一个
【发布时间】:2015-04-21 07:04:57
【问题描述】:

你怎么了黑帮?

我有以下代码似乎总是返回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 和其中的记录,我只想获取下一个和上一个值。

【问题讨论】:

  • 你试过!=吗?我认为它可能是在做一个参考平等..
  • 您可以为 T 类添加索引并通过索引获取下一个和上一个对象。你可以检查这个stackoverflow.com/questions/1869304/…
  • 这适用于整数数组...
  • 你检查过为什么返回null吗?您的代码表明只有在引发异常时才返回null。可以贴一下错误信息吗?
  • 是的,结果 linq to sql 不支持skipwhile。

标签: c# linq


【解决方案1】:

原因是 EntityFramework 不支持SkipWhile。

首先,要使用Skip 或Take,集合必须有一些才能使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);

通用版本在 System.Linq.Dynamic 上中继,可在 codeplex

上找到

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

【讨论】:

    【解决方案2】:

    也许我会因为这个解决方案而被钉死在十字架上(因为我觉得它有点脏)......但是......它可以工作(而且它没有使用 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);
        }
    }
    

    【讨论】:

    • 我会在任何我看到你写这段代码的地方开枪
    • @DarthVader 我说:被钉死……没有被枪杀。那是不公平的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-02
    • 2011-08-26
    • 2015-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多