'Mapping relationships using PetaPoco paging

I am using PetaPoco v5.1.228.0 and I am trying to fetch a list of people along with the category they belong to, using paging (30 items per page).

This is my code:

IEnumerable<Person> people;
var sql = new Sql("SELECT * FROM Person p INNER JOIN Category c ON p.CategoryId = c.Id");

using (var db = GetDatabaseConnection()) {
   var paging = db.Page<Person>(currentPage, 30, sql);
   people = paging.Items;
}

Person.cs

public class Person {
   public int Id { get; set; }
   public string Name { get; set; }
   public int CategoryId { get; set; }
   public Category Category { get; set; }
}

Category.cs

public class Category {
   public int Id { get; set; }
   public string Name { get; set; }
}

The problem is it won't populate the Category property within the Person object. As far as I know only db.Fetch allows multiple types to be specified, but in this case I would need to code the paging functionality myself.

What would be the best way to do it?



Solution 1:[1]

You can do it with an extention metod over IDatabase:

public static Page<TRet> PagedFetch<T1, T2, TRet>(this PetaPoco.IDatabase db, long page, long itemsPerPage, Func<T1, T2, TRet> cb, string sql, params object[] args)
        {
            SQLParts parts;
            if (!db.Provider.PagingUtility.SplitSQL(sql, out parts))
                throw new Exception("Unable to parse SQL statement for paged query");

            db.Provider.BuildPageQuery((page - 1) * itemsPerPage, itemsPerPage, parts, ref args);

            sql = string.Format("{0} offset {1} rows fetch next {2} rows only", sql, (page - 1) * itemsPerPage, itemsPerPage);

            var data = db.Fetch(cb, sql, args);

            var result = new Page<TRet>
            {
                Items = data,
                TotalItems = db.ExecuteScalar<long>(parts.SqlCount),
                CurrentPage = page,
                ItemsPerPage = itemsPerPage
            };

            result.TotalPages = result.TotalItems / itemsPerPage;

            if ((result.TotalItems % itemsPerPage) != 0)
                result.TotalPages++;

            return result;
        }

Solution 2:[2]

@Andres R: Useful answer, but code works for MSSQL only. Use this: string.Format("{0} LIMIT {2} OFFSET {1}", ...) for MySQL/SQLite/PostgreSQL/MSSQL 2012+.

It took me also some time to find how to use the Func<T1, T2, TRet> cb parameter, which is not covered in PetaPoco Fetch() documentation. It is a function, which simply fills your final entity with related entities from joined tables. Here is than an usage example

var page = PagedFetch<DataSet, User, DataSet>(
  page, 
  itemsPerPage, 
  (ds, usr) => { ds.user = usr; return ds; }, 
  sql, 
  whereArguments);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Andres R
Solution 2