How to order by a dynamic column name in EntityFramework?
Asked Answered
H

4

17

I am trying to get following code working , This was working fine for SQL Server, but since I changed to use MySQL, it is not working.

  records.Content = db.areas
                         .Where(x =>   x.Name.Contains(filter)))
                         .OrderBy("dated desc") 
                         .ToList();

I get the error:

Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.

string colName = "datedD" ; 

How to order by depending on colName variable?

Heligoland answered 27/6, 2016 at 13:23 Comment(4)
I guess by "string version" you mean the so called "Dynamic LINQ" (or System.Linq.Dynamic). Please add dynamic-linq tag and update the question accordingly.Orlantha
@Heligoland Can you please check my answer as it seems better method for this question ;DZoometry
try this library Entity Framework Plus Library - Linq-Dynamic. you can also check my answerCrookes
Duplicate: https://mcmap.net/q/11365/-dynamic-linq-orderby-on-ienumerable-lt-t-gt-iqueryable-lt-t-gt/861716Luxembourg
P
4

Try this

string filterString = "dated";
bool isAscSorting = false;

Func<dynamic, dynamic> orderingFunction = i =>
                                filterString == "dated" ? i.dated :
                                filterString == "something" ? i.columnx : "";

records.Content = (isAscSorting) ?
                      db.areas
                         .Where(x =>   x.Name.Contains(filter)))
                         .OrderBy(orderingFunction) 
                         .ToList()
                   :
                        db.areas
                         .Where(x =>   x.Name.Contains(filter)))
                         .OrderByDescending(orderingFunction) 
                         .ToList();
Panelboard answered 27/6, 2016 at 13:34 Comment(3)
Is it possible to stop duplication of this code ? db.areas .Where(x => x.Name.Contains(filter)))Heligoland
You cant on this answer But You can use dynamic linq It is complexPanelboard
@Heligoland you can put result of db.areas.Where(x => x.Name.Contains(filter))) into local variable var query = ... and then use query = (isAscSorting) ? query.OrderBy(...) : query.OrderByDescending(...)Jann
Z
67

In .Net Core, we can use the EF.Property method to specify the name of the property as a string:

string sortColumn = "Price";

//IQueryable<Product> q = from p in myDbContext.Products select p;
q = q.OrderBy(p => EF.Property<object>(p, sortColumn));
Zoometry answered 23/7, 2018 at 14:7 Comment(3)
this should be the accepted answerDaciadacie
if you are not using .Net Core look at @Taher Rahgooy answer hereCrookes
it reduced my whole page query to single line. thanksProstomium
P
4

Try this

string filterString = "dated";
bool isAscSorting = false;

Func<dynamic, dynamic> orderingFunction = i =>
                                filterString == "dated" ? i.dated :
                                filterString == "something" ? i.columnx : "";

records.Content = (isAscSorting) ?
                      db.areas
                         .Where(x =>   x.Name.Contains(filter)))
                         .OrderBy(orderingFunction) 
                         .ToList()
                   :
                        db.areas
                         .Where(x =>   x.Name.Contains(filter)))
                         .OrderByDescending(orderingFunction) 
                         .ToList();
Panelboard answered 27/6, 2016 at 13:34 Comment(3)
Is it possible to stop duplication of this code ? db.areas .Where(x => x.Name.Contains(filter)))Heligoland
You cant on this answer But You can use dynamic linq It is complexPanelboard
@Heligoland you can put result of db.areas.Where(x => x.Name.Contains(filter))) into local variable var query = ... and then use query = (isAscSorting) ? query.OrderBy(...) : query.OrderByDescending(...)Jann
E
3

I used the mix of 2 answers by @NEER and @S.Serpooshan to aviod LINQ queries

IQueryable<area> filteredItems = db.areas.Where(x =>   x.Name.Contains(filter)));
IQueryable<area> orderedItems;
if (IsAscending)
{
    orderedItems = filteredItems.OrderBy(item => typeof(area).GetProperty(colName).GetValue(item).ToString());
}
else
{
    orderedItems = filteredItems.OrderByDescending(item => typeof(area).GetProperty(colName).GetValue(item).ToString());
}

The bad thing is - my code is comparing items as strings. I had no time to make it more "type-friendly", but I'm pretty sure it is possible.

Evermore answered 23/1, 2020 at 22:59 Comment(1)
THIS is the Correct answer. also Item => Item.GetType() can be use instead of item => typeof(area)Glia
C
1

For dynamic ordering most convenient way I found:

string propertyNameForOrdering = "UserName";

var list = context.Customers.OrderByDescendingDynamic(x => "x." + propertyNameForOrdering).ToList(); // DESC

var list = context.Customers.OrderByDynamic(x => "x." + propertyNameForOrdering).ToList(); // ASC

Entity Framework Plus Library - Linq-Dynamic

That feature is free even for commercial use.

Crookes answered 18/12, 2020 at 9:50 Comment(2)
Are you sure it's still free and will remain so? Despite the name, that's not related to the EF team and the company behind it has a habit of picking up abandoned projects and dual-licensing them. Or creating "documentation" sites for other people's projects that promote their own unrelated libraries, like they did with DapperDawes
For example, when did "BulkInsert" become a paid extension?Dawes

© 2022 - 2024 — McMap. All rights reserved.