Apply OrderBy with DbSet
Asked Answered
S

2

8

I am trying to implement pagination and sorting with generic repository. How to take primary key column as default order by column in DbSet ?

DbSet = Context.Set<T>();

public IQueryable<T> GetAll(int pageNumber = 0, int pageSize = 10, string sortColumn = "")
{
    return DbSet.OrderBy("how to use primary key column here").Skip(pageNumber * pageSize)Take(pageSize);
}
Spellbound answered 24/10, 2014 at 15:14 Comment(1)
side note, I'm pretty sure you'll want Skip then TakeManda
S
9

I have used these extension methods to achieve something similar:

public static string GetKeyField(Type type)
{
    var allProperties = type.GetProperties();

    var keyProperty = allProperties.SingleOrDefault(p => p.IsDefined(typeof(KeyAttribute)));

    return keyProperty != null ? keyProperty.Name : null;
}

public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string orderBy)
{
    return source.GetOrderByQuery(orderBy, "OrderBy");
}

public static IQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string orderBy)
{
    return source.GetOrderByQuery(orderBy, "OrderByDescending");
}

private static IQueryable<T> GetOrderByQuery<T>(this IQueryable<T> source, string orderBy, string methodName)
    {
        var sourceType = typeof(T);
        var property = sourceType.GetProperty(orderBy);
        var parameterExpression = Expression.Parameter(sourceType, "x");
        var getPropertyExpression = Expression.MakeMemberAccess(parameterExpression, property);
        var orderByExpression = Expression.Lambda(getPropertyExpression, parameterExpression);
        var resultExpression = Expression.Call(typeof(Queryable), methodName,
                                               new[] { sourceType, property.PropertyType }, source.Expression,
                                               orderByExpression);

        return source.Provider.CreateQuery<T>(resultExpression);
    }

This allows you to pass the property name as a string and build up an expression which it passes to the regular LINQ OrderBy() function. So in your case, the usage would be:

DbSet = Context.Set<T>();

public IQueryable<T> GetAll(int pageNumber = 0, int pageSize = 10, string sortColumn = "")
{
    return DbSet.OrderBy(GetKeyField(typeof(T))).Skip(pageNumber * pageSize)Take(pageSize);
}

This assumes your key field in your entity class is properly decorated with the Key attribute.

Selfaddressed answered 24/10, 2014 at 15:24 Comment(3)
Great and flexible solution, saved me lots of time. Thank you!Collusive
Works like a charm. Thank you!Vaginectomy
How does this even work? Shouldn't Order By return an IOrderedQueryable, This solution doesn't look like it handles compound KeysFreestone
M
0

One way would be to have all your entities inherit from some interface that allows you to retrieve their primary key value :

public interface IIdentifiableEntity 
{
    public int Id {get; set;}
}

Then implementations would be like :

public class User : IIdentifiableEntity
{
   public int UserId {get; set;}

   //other properties...

   public int Id { get { return UserId; } set { UserId = value; } } 
}

Then it would be as easy as ordering by the Id. This pattern can help you in other areas as well.

Manda answered 24/10, 2014 at 15:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.