是否可以使用JoinSqlBuilder进行分页?

时间:2014-06-05 09:05:33

标签: servicestack ormlite-servicestack

我有一个非常正常的连接,我通过JoinSqlBuilder创建

var joinSqlBuilder = new JoinSqlBuilder<ProductWithManufacturer, Product>()
                    .Join<Product, Manufacturer>(sourceColumn: p => p.ManufacturerId,
                                                 destinationColumn: mf => mf.Id,
                                                 sourceTableColumnSelection: p => new { ProductId = p.Id, ProductName = p.Name },
                                                 destinationTableColumnSelection: m => new { ManufacturerId = m.Id, ManufacturerName = m.Name })

当然,由此创建的连接可能会返回很多行,所以我想使用分页 - 最好是在服务器端。但是,我在JoinSqlBuilder中找不到任何可以让我这样做的东西?我是否遗漏了某些东西,或者JoinSqlBuilder是否还没有支持这个(还)?

1 个答案:

答案 0 :(得分:3)

如果您不使用MS SQL Server,我认为以下内容可行。

var sql = joinSqlBuilder.ToSql();
var data = this.Select<ProductWithManufacturer>(
                 q => q.Select(sql)
                       .Limit(skip,rows)
           );

如果您正在使用MS SQL Server,它很可能会让您大吃一惊。我正在努力将类似于此的更优雅的解决方案合并到JoinSqlBuilder中。以下是一种快速而肮脏的方法来实现您的目标。

我创建了以下扩展类:

public static class Extension
{

    private static string ToSqlWithPaging<TResult, TTarget>(
        this JoinSqlBuilder<TResult, TTarget> bldr,
        string orderColumnName,
        int limit,
        int skip)
    {
        var sql = bldr.ToSql();

        return string.Format(@"
                 SELECT * FROM (
                    SELECT ROW_NUMBER() OVER (ORDER BY [{0}]) As RowNum, *
                        FROM (
                            {1}
                            )as InnerResult
                        )as RowConstrainedResult
                    WHERE RowNum > {2} AND RowNum <= {3}
            ", orderColumnName, sql, skip, skip + limit);
    }

    public static string ToSqlWithPaging<TResult, TTarget>(
        this JoinSqlBuilder<TResult, TTarget> bldr,
        Expression<Func<TResult, object>> orderSelector,
        int limit,
        int skip)
    {

        var member = orderSelector.Body as MemberExpression;
        if (member == null)
            throw new ArgumentException(
                "TResult selector refers to a non member."
                );

        var propInfo = member.Member as PropertyInfo;
        if (propInfo == null)
            throw new ArgumentException(
                "TResult selector refers to a field, it must be a property."
                );

        var orderSelectorName = propInfo.Name;

        return ToSqlWithPaging(bldr, orderSelectorName, limit, skip);
    }
}

应用如下:

List<Entity> GetAllEntities(int limit, int skip) 
{
   var bldr = GetJoinSqlBuilderFor<Entity>();
   var sql = bldr.ToSqlWithPaging(
                     entity => entity.Id,
                     limit,
                     skip);
   return this.Db.Select<Entity>(sql);
}