multiple orderby column of string by linq - linq

i have string that contain column name for sorting with linq,
it work fine when string contain just one column,but when contain with multiple column i don't knwon how can i create linq statement for sorting them.
my string like this : "ClassNo ASC, count DESC, floor ASC"
i try sorting like below if one column:
switch (sort.Trim())
{
default:
result = result.OrderBy(u => u.ClassId);
break;
case "ClassNo DESC":
result = result.OrderByDescending(u => u.ClassNo);
break;
case "ClassNo ASC":
result = result.OrderBy(u => u.ClassNo);
break;
case "count DESC":
result = result.OrderByDescending(u => u.count);
break;
case "count ASC":
result = result.OrderBy(u => u.count);
break;
case "floor DESC":
result = result.OrderByDescending(u => u.floor);
break;
case "floor ASC":
result = result.OrderBy(u => u.floor);
break;
case "ClassId DESC":
result = result.OrderByDescending(u => u.ClassId);
break;
}

You can do something like this:
var ordered1 = result.OrderBy(x => x.count);
var ordered2 = ordered1.ThenBy(x => x.floor);
var ordered3 = ordered2.ThenByDescending(x => x.ClassId);
The thing to note here is that OrderBy() or OrderByDescending() returns an IOrderedEnumerable<T>, which you can then add another level of ordering to.
So in your case, it would be something like this:
// convert to an IOrderedEnumerable<T>
var orderedResult = result.OrderBy(x => 1);
foreach (string part in sort.Split(','))
{
switch (part.Trim())
{
case "ClassNo DESC":
orderedResult = orderedResult.ThenByDescending(u => u.ClassNo);
break;
case "ClassNo ASC":
orderedResult = orderedResult.ThenBy(u => u.ClassNo);
break;
case "count DESC":
orderedResult = orderedResult.ThenByDescending(u => u.count);
break;
case "count ASC":
orderedResult = orderedResult.ThenBy(u => u.count);
break;
case "floor DESC":
orderedResult = orderedResult.ThenByDescending(u => u.floor);
break;
case "floor ASC":
orderedResult = orderedResult.ThenBy(u => u.floor);
break;
case "ClassId DESC":
orderedResult = orderedResult.ThenByDescending(u => u.ClassId);
break;
default:
orderedResult = orderedResult.ThenBy(u => u.ClassId);
break;
}
}

Related

Search for particular column and update it in linq EF 4.0

Basically table contain about 50 columns and I have to search for that particular column and update it.
lets say val == 27 then columnName will be Alarm27 and the "onOff" value I have to set in that Alarm27 column.
But question is how do I get this Alarm27 and just update it.
This is what I have tried so far.
public void UpdateAlarm(int val, bool onOff)
{
string alarmName = "Alarm" + val;
using (ESEntities context = new ESEntities())
{
var alarmid = context.OffShoreAlarms.Where(p => p.StationID == (int)TMStation.LQ).Select(p => p.OSAlarmID).FirstOrDefault();
var alarmMonitor = context.OfSAlarmMonitors.Where(p => p.OSAlarmID == alarmid).Select(p => p).FirstOrDefault();
switch (val)
{
case 1:
alarmMonitor.Alarm1 = onOff;
context.saveChanges();
break;
case 2:
alarmMonitor.Alarm2 = onOff;
context.SaveChanges();
break;
.
.
.
.
case 50:
alarmMonitor.alarm50 = onOff;
context.saveChanges();
break;
}
//TODO: context.SaveChanges(); do update operation..
}
}
I have not practically tried this but I think this may work for you.
string alarmName = "Alarm" + val;
context.OffShoreAlarms.Property(alarmName).CurrentValue = true;
You can change current Value of Your entity like this.
For more info check this Link

C# linq and sorting

With linq I want to use order by with specific column but I need two switches because i don't know how to use desc or asc in one
public class CustomersRepository : RepositoryBase<Customers>
{
public List<Customers> GetAll(CustomersProperties property, SortEnum sortEnum, int page, int limit)
{
var query = _context.Set<Customers>();
switch (sortEnum)
{
case SortEnum.Ascending:
switch (property)
{
case CustomersProperties.Name:
query = query.OrderBy(x => x.Name);
break;
case CustomersProperties.Surname:
query = query.OrderBy(x => x.Lastname);
break;
default:
throw new ArgumentOutOfRangeException("property");
}
break;
case SortEnum.Descending:
break;
default:
throw new ArgumentOutOfRangeException("sortEnum");
}
return query.Skip(page * limit)
.Take(limit).ToList();
}
}
Is it possible to do without two switch cases?
Be aware that query.OrderBy(x => x.Name); does not do anything since the sorted collection is returned from OrderBy, and you're not capturing that return.
That said, there's not a way to "dynamically" choose the direction in Linq. However, a conditional switch would be a little cleaner. Another option would be to capture the sort expression in a variable:
Expreccion<Func<Customers, string>> propExp;
switch (property)
{
case CustomersProperties.Name:
propExp = ((Customers)x => x.Name)
break;
case CustomersProperties.Surname:
propExp = ((Customers)x => x.Lastname);
break;
default:
throw new ArgumentOutOfRangeException("property");
}
query = sortEnum == SortEnum.Ascending
? query.OrderBy(propExp);
: query.OrderByDescending(propExp);
You could make your own overload, something like this:
public static IOrderedQueryable<TSource> OrderBy<TSource, TKey>(
this IQueryable<TSource> source,
Expression<Func<TSource, TKey>> keySelector, SortEnum sort) {
switch (sort) {
case SortEnum.Ascending:
return source.OrderBy(keySelector);
case SortEnum.Descending:
return source.OrderByDescending(keySelector);
default:
throw new ArgumentOutOfRangeException("sort");
}
}
// later on..
query = query.OrderBy(x => x.LastName, sortEnum);
You can prepare sortProperty Expression first and then use it with either OrderBy or OrderByDescending:
public List<Customers> GetAll(CustomersProperties property, SortEnum sortEnum, int page, int limit)
{
var query = _context.Set<Customers>();
Expression<Func<Customers, string>> sortProperty;
switch (property)
{
case CustomersProperties.Name:
sortProperty = x => x.Name;
break;
case CustomersProperties.Surname:
sortProperty = x => x.Lastname;
break;
default:
throw new ArgumentOutOfRangeException("property");
}
switch (sortEnum)
{
case SortEnum.Ascending:
query = query.OrderBy(sortProperty);
break;
case SortEnum.Descending:
query = query.OrderByDescending(sortProperty);
break;
default:
throw new ArgumentOutOfRangeException("sortEnum");
}
return query.Skip(page * limit)
.Take(limit).ToList();
}

How to optimize code for Sorting?

I would like to optimize following lines of code for Sorting.
public ViewResult Index(string sortorder, int? pagesize, int? page)
{
int pageSize = pagesize ?? 10;
if (Request.HttpMethod != "GET")
{
page = 1;
pageSize = 10;
}
ViewBag.SelectedPageSize = pageSize;
ViewBag.CurrentSort = sortorder;
ViewBag.FirstNameSortParm = String.IsNullOrEmpty(sortorder) ? "FirstName desc" : "";
ViewBag.LastNameSortParm = sortorder == "LastName" ? "LastName desc" : "LastName";
ViewBag.DepNameSortParm = sortorder == "depName" ? "depName desc" : "depName";
var joined = from tm in db.TabMasters select tm;
switch (sortorder)
{
case "FirstName":
joined = joined.OrderBy(m => m.FirstName);
break;
case "FirstName desc":
joined = joined.OrderByDescending(m => m.FirstName);
break;
case "LastName":
joined = joined.OrderBy(m => m.LastName);
break;
case "LastName desc":
joined = joined.OrderByDescending(m => m.LastName);
break;
case "depName":
joined = joined.OrderBy(m => m.depName);
break;
case "depName desc":
joined = joined.OrderByDescending(m => m.depName);
break;
default:
joined = joined.OrderBy(m => m.FirstName);
break;
}
int pageIndex = (page ?? 1) - 1;
int start = (pageIndex * pageSize);
ViewBag.TotalRecord = joined.Count();
ViewBag.StartRecord = start + 1;
ViewBag.EndRecord = ((start + pageSize) >= ViewBag.TotalRecord) ? ViewBag.TotalRecord : (start + pageSize);
return View(joined.ToPagedList(pageIndex, pageSize));
}
Because this is very tedious way if i have more the 10 fields to perform sort.
Thanks,
Imdadhusen
It's a bit vague to me what your actual goal is but for the switch part you could use an extension method as the below.
public static class SortExtensions
{
public static IEnumerable<T> SortByField<T>(this IEnumerable<T> sequence, string sortOrder)
{
var tokens = sortOrder.Trim().Split(' ');
var field = tokens[0];
var direction = tokens.Skip(1).Single().ToLower();
var prop = typeof(T).GetProperty(field);
return direction == "desc"
? sequence.OrderByDescending(m => prop.GetValue(m, null))
: sequence.OrderBy(m => prop.GetValue(m, null));
}
}
It will make a very simplified parsing of the sort order. It puts the responsibility on the calling party which is generally not what you want to do, so you might want some error handling in case the sortorder string does not fulfill the requirements.
from the sortorder string it fetches a name used to identify a property which can be used to fetch the value used for sorting.
you can use it like this:
db.TabMasters.SortByField(sortOrder)
EDIT based on comment:
The line typeof(T).GetProperty(field) is fragile in the absence of any error handling. It relies on the first token to be a name of a public property of the type T. It will return null if the name doesn't match a property. Including if it matches a Field name. A similar function exist for getting a FieldInfo
prop.GetField(field) will return a fieldinfo object of there's a public field with the given name otherwise null. To get the value of a field simply omit the last parameter to the GetValue call.
You should take a look at Linq.DynamicQuery.
There's more info in this blogpost http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
The library lets you write following code:
var query = northwind.Products
.Where("CategoryID = 3 AND UnitPrice > 3")
.OrderBy("SupplierID");
instead of
var query = from p in northwind.Products
where p.CategoryID == 3 && p.UnitPrice > 3
orderby p.SupplierID
select p;
If you want to add the sortdirection:
var query = northwind.Products.OrderBy("SupplierID Descending");

Linq Sort with Text value, not lambda

MVC3 website. EF4.1 Code First.
I am saving the sort column and direction off to session, so that when the user comes back to the page the grid is still in the same sort order.
I want to be able to specify how to sort the collection with the values I have saved like so.
this.Issues = this.db.ITIssues.Orderby(this.sort + " " + this.sortdir)...
Currently I have to use a switch statement and handle every different combination of fields + sort direction.
Is there a better way?
switch (this.Sort)
{
case "ITApplication.Name":
if (this.SortDir == "ASC")
this.Issues = this.db.ITIssues.OrderBy(i => i.ITApplication.Name).Where(i => i.ITAppGroupID == this.ITAppGroupID);
else
this.Issues = this.db.ITIssues.OrderByDescending(i => i.ITApplication.Name).Where(i => i.ITAppGroupID == this.ITAppGroupID);
break;
case "ITIssueType.Name":
if (this.SortDir == "ASC")
this.Issues = this.db.ITIssues.OrderBy(i => i.ITIssueType.Name).Where(i => i.ITAppGroupID == this.ITAppGroupID);
else
this.Issues = this.db.ITIssues.OrderByDescending(i => i.ITIssueType.Name).Where(i => i.ITAppGroupID == this.ITAppGroupID);
break;
case "CurrentStatus.Name":
if (this.SortDir == "ASC")
this.Issues = this.db.ITIssues.OrderBy(i => i.CurrentStatus.Name).Where(i => i.ITAppGroupID == this.ITAppGroupID);
else
this.Issues = this.db.ITIssues.OrderByDescending(i => i.CurrentStatus.Name).Where(i => i.ITAppGroupID == this.ITAppGroupID);
break;
case "CurrentAssignedTo.Fname":
if (this.SortDir == "ASC")
this.Issues = this.db.ITIssues.OrderBy(i => i.CurrentAssignedTo.Fname).Where(i => i.ITAppGroupID == this.ITAppGroupID);
else
this.Issues = this.db.ITIssues.OrderByDescending(i => i.CurrentAssignedTo.Fname).Where(i => i.ITAppGroupID == this.ITAppGroupID);
break;
case "CreatedBy.Fname":
if (this.SortDir == "ASC")
this.Issues = this.db.ITIssues.OrderBy(i => i.CreatedBy.Fname).Where(i => i.ITAppGroupID == this.ITAppGroupID);
else
this.Issues = this.db.ITIssues.OrderByDescending(i => i.CreatedBy.Fname).Where(i => i.ITAppGroupID == this.ITAppGroupID);
break;
case "CurrentPriority.Name":
if (this.SortDir == "ASC")
this.Issues = this.db.ITIssues.OrderBy(i => i.CurrentPriority.Name).Where(i => i.ITAppGroupID == this.ITAppGroupID);
else
this.Issues = this.db.ITIssues.OrderByDescending(i => i.CurrentPriority.Name).Where(i => i.ITAppGroupID == this.ITAppGroupID);
break;
default:
this.Issues = this.db.ITIssues.OrderByDescending(i => i.ID).Where(i => i.ITAppGroupID == this.ITAppGroupID);
break;
}
I've had to do something similar recently, what you are looking for is Dynamic Linq! Take a look at this:
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
There seems to be two obstacles with your code, the first involves getting a property name from the string represented by this.Sort. That's probably going to involve some reflection code. The second part involves shortening the amount of code needed to specify ascending sort vs descending sort.
You could do this is several ways. The first idea I thought of was to make an extension method for OrderBy which took in a bool SortDir argument. There are a few overloads for OrderBy allowing for Func<T,TKey> KeySelectors and an IComparer<T>. I'll show you the simple one with just a keySelector, but you may want to implement all of them for a fully generic solution
public static class IEnumerableExtentions
{
public static IEnumerable<T> OrderBy<T,TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector, bool reverse)
{
return reverse ? source.OrderByDescending(keySelector) : source.OrderBy(keySelector);
}
}
With this in place, you could write your code without all those if's
switch (this.Sort)
{
case "ITApplication.Name":
this.Issues = this.db.ITIssues.OrderBy(i => i.ITApplication.Name, this.SortDir == "ASC").Where(i => i.ITAppGroupID == this.ITAppGroupID);
break;
/*...*/
}
As a second solution to determining sort order, you pass in an IComparer which uses SortDir. Here's the IComparer implementation you could use
class ReversableComparer : IComparer<IComparable>
{
private bool _reverse;
public ReversableComparer(bool reverse)
{
_reverse = reverse;
}
public int Compare(IComparable x, IComparable y)
{
return _reverse ? y.CompareTo(x) : x.CompareTo(y);
}
}
Then you could write your code
switch (this.Sort)
{
case "ITApplication.Name":
this.Issues = this.db.ITIssues.OrderBy(i => i.ITApplication.Name, new ReversableComparer(this.SortDir != "ASC")).Where(i => i.ITAppGroupID == this.ITAppGroupID);
break;
/*...*/
}
That's a bit more code to write, but its there if you need it.
As far as the property name/reflection goes, if you're using Linq as part of Linq to SQL, the dynamic linq link provided by #AlbertVo might be worth a look. If you're working more with Linq to Objects, then instead of i => i.ITApplication.Name try playing with i => i.GetType().GetProperty(this.Sort).GetValue(i, null)
Of course you'll need System.Reflection to make that work and it may be slower than your original solution.
I hope some of that helped. Cheers.
EDIT
As a summary, these two techniques can be combined. Your final code might look like this:
public static class IEnumerableExtentions
{
public static IEnumerable<T> OrderBy<T,TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector, bool reverse)
{
return reverse ? source.OrderByDescending(keySelector) : source.OrderBy(keySelector);
}
}
void Main()
{
this.Issues = this.db.ITIssues
.OrderBy(i => i.GetType().GetProperty(this.Sort).GetValue(i, null),
this.SortDir == "ASC")
.Where(i => i.ITAppGroupID == this.ITAppGroupID);
}

Dynamic LINQ help for sorting problem

I have a simple IEnumerable collection of Order objects. I want to write a generic sort function that accepts the collection and a sortkey that corresponds to a property on an Order object. I don't want to hardcode the sort instructions for every property. How can I build a dynamic LINQ string that automatically generates the LINQ for me? Here is my SortOrders() function in its current state:
public IEnumerable<Order> SortOrders(IEnumerable<Order> orders, string sortKey)
{
// Sort order records
try
{
IEnumerable<Order> sortedOrders = new List<Order>();
// Extract sort key and direction from combined sortKey input
string _sortKey = this.SortKey.Replace(" ASC", "").Replace(" DESC", "");
bool sortASC = this.SortKey.EndsWith(" ASC");
switch (_sortKey)
{
case "CustomerID":
sortedOrders = (sortASC) ? orders.OrderBy(o => o.CustomerID) : orders.OrderByDescending(o => o.CustomerID);
break;
case "CustomerAddress":
sortedOrders = (sortASC) ? orders.OrderBy(o => o.CustomerAddress) : orders.OrderByDescending(o => o.CustomerAddress);
break;
case "CustomerCity":
sortedOrders = (sortASC) ? orders.OrderBy(o => o.CustomerCity) : orders.OrderByDescending(o => o.CustomerCity);
break;
default:
sortedOrders = orders;
break;
}
return sortedOrders;
}
catch
{
return orders; // return original orders list in the event of errors
}
}
I am looking to replace all of the case sections like this:
case "CustomerID":
sortedOrders = (sortASC) ? orders.OrderBy(o => o.CustomerID) : orders.OrderByDescending(o => o.CustomerID);
with a single directive like this:
sortedOrders = (sortASC) ? orders.OrderBy(o => o.PropertyName) : orders.OrderByDescending(o => o.PropertyName);
You can pass the expression you want to sort in as a Lamba (this is simplified/pseudocode)
SortOrders(IEnumerable<Order> orders, Func<Order, string> func)
{
sortedOrders = orders.OrderBy(func)
....
}
// call:
SortOrders(orders, o => o.CustomerID);
You can use Dynamic LINQ and there's no need for the extension method. Just use the extension in the DynamicQueryable class and specify both the key and direction as a string.
var sorted = orders.OrderBy( "CustomerID desc" );

Resources