What do you think about the following approach to CRUD? Here is the reading+pagination example. DTO types have Dto* prefix, EF Entity Types have E* prefix.DAL example:class UserQuery : PagingQuery{   public int CompanyId { get; set; }}interface IUserReader{   IPage<DtoUser> Read(UserQuery query);}class UserReader : IUserReader{    public IPage<DtoUser> Read(UserQuery query) =>        EUsers()            .Where(u => u.CompanyId == query.CompanyId)            .OrderBy(u => u.LastLoginAt)                .AsPage(query, u => u.ToDto());          IQueryable<EUser> EUsers() =>       new EContext()          .Users          .Include(u => u.Certificates)          .AsNonTracking();}static class UserMapper{   public static DtoUser ToDto(this EUser e) =>      new DtoUser       {         Id = e.Id,         Name = e.Name,        Certificates = e.Certificates.Select(c => c.ToDto())      };} static class CertificateMapper{   public static DtoCertificate ToDto(this ECertificate e) =>      new DtoCertificate       {         Id = e.Id,         Name = e.Name       };} where library code for pagination is (feel free to borrow if it works for you :)public class PagingQuery{    int _pageSize;    int _page;    protected PagingQuery()    {        _pageSize = 25;        _page = 1;    }    public int PageSize    {        get { return _pageSize; }        set        {            if (value <= 0)                throw new ArgumentOutOfRangeException(                   PageSize must be bigger than 0.);            if (value > 1000)                throw new ArgumentOutOfRangeException(                   PageSize must be less than 1000.);            _pageSize = value;        }    }    public int Page    {        get { return _page; }        set        {            if (value <= 0)                throw new ArgumentOutOfRangeException(                    Page must be bigger than 0.);            _page = value;        }    }}public interface IPage<T> : IEnumerable<T>{    Pagination Pagination { get; }}class Page<T> : IPage<T>{    public Page(Pagination pagination, IEnumerable<T> items)    {        Pagination = pagination;        Items = items;    }    public Pagination Pagination { get; }    IEnumerable<T> Items { get; }    public IEnumerator<T> GetEnumerator() => Items.GetEnumerator();    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();}public static class Page{    public static IPage<TResult> AsPage<T, TResult>(        this IQueryable<T> source,         PagingQuery query,         Func<T, TResult> selector) =>        source            .AsPage(query)            .Select(selector);    public static IPage<T> AsPage<T>(        this IQueryable<T> source,         PagingQuery query) =>        new Page<T>(            new Pagination(query, source.Count()),            source                 .Skip((query.Page - 1) * query.PageSize)                 .Take(query.PageSize)                 .AsEnumerable());    public static IPage<TResult> Select<T, TResult>(        this IPage<T> source,         Func<T, TResult> selector) =>        new Page<TResult>(            source.Pagination,            source                .AsEnumerable()                .Select(selector));    public static IPage<TResult> ToPage<T, TResult>(        this IQueryable<T> source,         PagingQuery query,         Func<T, TResult> selector) =>        source            .AsPage(query, selector)            .Load();    public static IPage<T> ToPage<T>(        this IQueryable<T> source,         PagingQuery query) =>        source            .AsPage(query)            .Load();    static IPage<T> Load<T>(this IPage<T> source) =>        new Page<T>(            source.Pagination,            source.ToArray());}public class Pagination{    public Pagination(PagingQuery query, int total)    {        Page = query.Page;        PageSize = query.PageSize;        Total = total;    }    public int Page { get; set; }    public int PageSize { get; private set; }    public int Total { get; private set; }    public int Pages    {        get { return (int)Math.Ceiling((double)Total / (double)PageSize); }    }}
A clean way to do CRUD with pagination
c#;pagination;crud