【问题标题】:Generalize without losing type泛化而不丢失类型
【发布时间】:2017-01-12 19:16:35
【问题描述】:

我需要将这两种方法合并为一个泛化它们。我知道 IQueryable 实现了 IEnumerable,IOrderedQueryable 实现了 IOrderedEnumerable,如果存在第二种方法,第一种方法似乎没用。但是由于某些实体框架的原因,第二个破坏了服务器端查询转换(Linq-to-SQL)

    private static IQueryable<T> Pag<T>(IOrderedQueryable<T> data, int totalRows, int reqLength, int pageNum)
    {
        if (reqLength == 0)
            return data;
        else
        {
            int skipRows = reqLength * (pageNum - 1);
            if (skipRows >= totalRows)
                skipRows = 0;
            int diff = totalRows - skipRows;
            return data.Skip(skipRows).Take(diff > reqLength ? reqLength : diff);
        }
    }

    private static IEnumerable<T> Pag<T>(IOrderedEnumerable<T> data, int totalRows, int reqLength, int pageNum)
    {
        if (reqLength == 0)
            return data;
        else
        {
            int skipRows = reqLength * (pageNum - 1);
            if (skipRows >= totalRows)
                skipRows = 0;
            int diff = totalRows - skipRows;
            return data.Skip(skipRows).Take(diff > reqLength ? reqLength : diff);
        }
    }

这些方法违反了DRY 规则,非常烦人。

【问题讨论】:

  • 您的代码混淆成功。学习使用自我描述的变量名称。话虽如此,请展示您如何调用此代码。
  • 您需要展示一个完整、可缩小且可验证的示例,以显示 EF 无法在 Linq 中转换为 SQL。
  • 此代码只是对数据库查询的结果进行分页。如果 linq 在 IQueryable 集合上工作,则 linq-to-sql 会从数据库中检索所需的行。注释 IQueryable 方法后,代码仍然可以使用 IEnumerable 方法工作,但查询会从数据库处理本身检索所有数据,而不是将作业留给数据库,从而对性能产生不利影响。
  • 为什么需要指定totalRows? Take(diff > reqLength ? reqLength : diff) Take 中的条件计数不是必需的(对于 IEnumerable 来说绝对是),我相信大多数其他 DataProviders 都是这种情况。它可能只是 Take(totalRows).Skip(...).Take(reqLength) 因为如果您指定的值大于可用的值,则该参数是允许的。
  • 我之前在代码中使用过 Count()。最好不要在必要时调用它。

标签: c# linq linq-to-sql generalization


【解决方案1】:

即使代码看起来相同,它们也不适用于相同的类型,也不能使用泛型,因为 where 子句只能 AND 组合多个给定值。

所以你能做的就是把计算逻辑分解出来,但是这是否真的更好的可读性和可维护性真的取决于你的态度。

private static bool TryCalculateRange(int totalCount, int pageLength, int page, out int skip, out int take)
{
    skip = 0;
    take = 0;

    if(pageLength <= 0)
        return false;

    skip = pageLength * (page - 1);

    if(skip >= totalCount)
        skip = 0;

    take = totalCount - skip;

    if(take > pageLength)
        take = pageLength;

    return true;
}

public static IQueryable<T> Pag<T>(IOrderedQueryable<T> data, int totalRows, int reqLength, int pageNum)
{
    int skip;
    int take;

    return TryCalculateRange(totalRows, reqLength, pageNum, out skip, out take))
           ? data.Skip(skip).Take(take)
           : data;
}

public static IEnumerable<T> Pag<T>(IOrderedEnumerable<T> data, int totalRows, int reqLength, int pageNum)
{
    int skip;
    int take;

    return TryCalculateRange(totalRows, reqLength, pageNum, out skip, out take))
           ? data.Skip(skip).Take(take)
           : data;
    }
}

【讨论】:

    猜你喜欢
    • 2019-05-26
    • 2020-10-03
    • 2021-07-23
    • 1970-01-01
    • 2013-11-17
    • 2012-06-14
    • 2020-02-05
    • 2021-07-13
    • 1970-01-01
    相关资源
    最近更新 更多