2
\$\begingroup\$

I am using Entity Framework Core as ORM in my ASP.NET Core 2.1 project. I want to perform server-side pagination in Career Controller for getting list of careers. I have a model which looks like:

 public class Career
    {
        private string _title, _description;

        [Key]
        public long career_id { get; set; }
        [Required]
        [MaxLength(50)]
        public string title
        {
            get => _title;
            set
            {
                if (string.IsNullOrWhiteSpace(value))
                {
                    throw new NonEmptyValueException("Title is required.");
                }
                _title = value;
            }
        }

        [Required]
        public DateTime opening_date { get; set; } = DateTime.Now;
        public DateTime? closing_date { get; set; }

        [Required]
        [MaxLength(2000)]
        public string description
        {
            get => _description;
            set
            {
                if (string.IsNullOrWhiteSpace(value))
                {
                    throw new NonEmptyValueException("Description is required.");
                }
                _description = value;
            }
        }

        [MaxLength(70)]
        public string image_name { get; set; }

        public bool is_closed { get; set; } = false;

        public void markClosed()
        {
            is_closed = true;
            closing_date = DateTime.Now;
        }

        public void markUnclosed()
        {
            is_closed = false;
            closing_date = null;
        }
    }

This is how my DbContext looks like:

 public class AppDbContext : DbContext
    {
        public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
        {

        }    
        public DbSet<Career> careers { get; set; }
    }

Currently, I am doing this way to perform server side pagination in Controller:

public IActionResult Index(CareerFilter filter = null)
        {
            try
            {
                var careers = _careerRepo.getQueryable();

                if (!string.IsNullOrWhiteSpace(filter.title))
                {
                    careers = careers.Where(a => a.title.Contains(filter.title));
                }

                careers = careers.Where(a => a.opening_date >= filter.from_date && a.opening_date <= filter.to_date);

                ViewBag.pagerInfo = _paginatedMetaService.GetMetaData(careers.Count(), filter.page, filter.number_of_rows);


                careers = careers.Skip(filter.number_of_rows * (filter.page - 1)).Take(filter.number_of_rows);

                return View(careers.ToList());
            }
            catch (Exception ex)
            {
                AlertHelper.setMessage(this, ex.Message, messageType.error);
                return Redirect("/admin");
            }
        }

This is how my getQueryable() method in repository looks like:

public IQueryable<Career> getQueryable()
{
 return _appDbContext.Set<Career>();
}

I am personally not satisfied with the way I am exposing queryable and performing all conditional query concatenation in Controller. Controllers looked messy with increase in number of conditions. Please suggest me a better way to perform same action.

\$\endgroup\$
  • 2
    \$\begingroup\$ I would only expose IQueryable for CQRS endpoints. In a system, I would prefer to create a DataLayer that exposes IEnumerable to upper layers. The filters would be performed in this layer. \$\endgroup\$ – dfhwze May 20 at 18:53
  • \$\begingroup\$ Why not just use OData to support paging against your web api. docs.microsoft.com/en-us/aspnet/web-api/overview/… and youtube.com/watch?v=ZCDWUBOJ5FU are good places to read up on it. Also with @dfhwze that if going to expose IQueryable then go the CQRS route. You don't have to use a framework you can build a simple one yourself if you don't want to take on extra dependency right now. \$\endgroup\$ – CharlesNRice May 20 at 21:47
  • \$\begingroup\$ One other remark I have: if you have a lot of operations with the same functionality in the try-catch block, you might want to consider AOP msdn.microsoft.com/en-us/magazine/dn574804.aspx for intercepting exceptions for all operations. \$\endgroup\$ – dfhwze May 21 at 17:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.