we have written a Generic function to get the records from EF code first in a repository pattern. Rest seems to be ok but when passing an Integer to the dynamic order by , it says Cannot cast System.Int32 to System.Object
the expression is as follows:
Expression<Func<HeadOffice, object>> orderByFunc = o => o.Id;
if (options.sort == "Id")
{
// this is an Integer
orderByFunc = o => o.Id;
}
if (options.sort =="Name")
{
// string
orderByFunc = o => o.Name;
}
if (options.sort == "Code")
{
orderByFunc = o => o.Code;
}
the generic method is as follows:
public virtual IEnumerable<TEntity> GetSorted<TSortedBy>(
Expression<Func<TEntity, object>> order,
int skip, int take,
params Expression<Func<TEntity, object>>[] includes)
{
IQueryable<TEntity> query = dbSet;
foreach (var include in includes)
{
query = dbSet.Include(include);
}
IEnumerable<TEntity> data = query.OrderBy(order).Skip(skip).Take(take).ToList();
return data;
}
if we convert Expression<Func<TEntity, object>>
to Expression<Func<TEntity, int>>
then it seems to work fine with integer but consequently not with strings
any help appreciated.
Maybe if you change the type of that parameter for this Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy
, it could make your life easier:
public virtual IEnumerable<TEntity> GetSorted(Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy,...)
{
IQueryable<TEntity> query = dbSet;
//...
if (orderBy != null)
{
query = orderBy(query);
}
//...
}
This way you can pass an Func
like this:
Func<IQueryable<HeadOffice>, IOrderedQueryable<HeadOffice>> orderBy=null;
if (options.sort == "Id")
{
orderBy= query=>query.OrderBy(o => o.Id);
}
//...
Another thing that I notice now is you are not using the TSortedBy
generic parameter, so, you could also do this:
public virtual IEnumerable<TEntity> GetSorted<TSortedBy>(Expression<Func<TEntity, TSortedBy>> order,
int skip, int take,
params Expression<Func<TEntity, object>>[] includes)
{
}
But anyway I think is better use the first option and remove that generic parameter.
Create a Sorter class. We also need a property-type-neutral base class:
public class SorterBase<TEntity>
{
public abstract IEnumerable<TEntity> GetSorted( // Note, no order argument here
int skip, int take,
params Expression<Func<TEntity, object>>[] includes);
}
public class Sorter<TEntity, TSortProp> : SorterBase<TEntity>
{
private Expression<Func<TEntity, TSortProp>> _order;
public Sorter(Expression<Func<TEntity, TSortProp>> order)
{
_order = order;
}
public override IEnumerable<TEntity> GetSorted(...)
{
// Use _order here ...
}
}
Now change the sort decision to:
SorterBase<HeadOffice> sorter;
if (options.sort == "Id") {
sorter = new Sorter<HeadOffice, int>(o => o.Id);
} else if (options.sort == "Name") {
sorter = new Sorter<HeadOffice, string>(o => o.Name);
}
...
var result = sorter.GetSorted(skip, take, includes);
One solution is to have two overloaded methods, one takes
Expression<Func<TEntity, int>>
and one takes
Expression<Func<TEntity, string>>
To minimize code duplication, extract common code (for example the query initialization statement and the for loop) to a shared method, and just let the two methods call this shared method and then invoke OrderBy on the result.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With