LINQ order by and then by - c#

my code :
var list3 = _ItemForCheckService
.GetBy(x => x.Status != Status.Deleted)
.OrderBy(x => x.Approver != null || x.Approver2 != null)
.ThenBy(x => x.ModifiedDate)
.ToList();
approver=guid approver2=guid modifieddate=datetime
if any of my list item has approver or approver2 value (Not null) it must be on top of my list.
if none of items has value of approver or approver2 they should be listed by their modified date (oldest is first).
in my code, it doesn't work.
Thanks.
Edit : I tried OrderByDesc still i don't see the
grouped approver or approver2 results
on the top or bottom of my page..they didn't grouped together

Without test data to pin down the error, a crystal ball required. You may have several issues here:
Since false < true you may want to use .OrderByDescending(...) instead of .OrderBy()
Since Guid is struct it can't be null (but can be compared with null to return true)
You may want to put on top items which have both Approver and Approver2 then items with single approver, then with none.
Code (assuming Approver as well as Approver2 are of type Guid):
var list3 = _ItemForCheckService
.GetBy(x => x.Status != Status.Deleted)
.OrderByDescending(x => x.Approver != default(Guid) || x.Approver2 != default(Guid))
.ThenBy(x => x.ModifiedDate)
.ToList();
or if we want to implement point 3.:
var list3 = _ItemForCheckService
.GetBy(x => x.Status != Status.Deleted)
.OrderBy(x => (x.Approver != default(Guid) ? 0 : 1) +
(x.Approver2 != default(Guid) ? 0 : 1))
.ThenBy(x => x.ModifiedDate)
.ToList();

Related

Sorting with Nulls Last

I have the following:
public IEnumerable<Customer> SortByRegion(IEnumerable<Customer> customerList)
{
return customerList.OrderBy(x => x.Region).ThenBy(x => x.ContactName);
}
It needs to Orderby Region, then by ContactName. But have the Null Regions at the bottom. I have tried the following:
customerList.OrderBy(x => x.Region != null).ThenBy(x => x.ContactName);
But id did not work. Been googling for a while. Cant seem to find it.
You can do something like this:
OrderBy(x => x.Region != null ? 1 : 0)
Well, since false < true for null last you can put
OrderBy(x => x.Region == null)

linq to entities skip after concat

I want to display results that don't have a secondary ID displayed first and then display items that do have a secondary ID. But then I need to Skip and Take.
IQueryable<thing> result;
IQueryable<thing> result2;
result2 = result
.Where(t => !(t.second_id == null || t.second_id.Trim() == string.Empty))
.OrderBy(t => t.second_id);
result = result
.Where(t => (t.second_id== null || t.second_id.Trim() == string.Empty))
.OrderBy(t => t.first_id);
result = result.Concat(result2);
return result
.Select(t => t.primary_key)
.Skip(pageSize * pageNumber)
.Take(pageSize)
.ToList();
The problem is that after Concat the IQueryable is no longer technically ordered so Skip and Take throw an error. Like this:
PagedList error: The method 'OrderBy' must be called before the method 'Skip'
You can do it in one query with the conditional operator:
return result.OrderBy(t => (t.second_id != null && t.second_id.Trim() != String.Empty))
.ThenBy(t => (t.second_id != null && t.second_id.Trim() != String.Empty) ? t.second_id : t.first_id)
.Select(t => t.primary_key)
.Skip(pageSize * pageNumber)
.Take(pageSize)
.ToList();
It would need some adjustment if you need to order duplicate second_id in some way, but your original code doesn't.
PS I folded in the negation operator since I think it reads more clearly.
You can do the job with a single query
result = result
.OrderByDescending(t => (t.second_id== null || t.second_id.Trim() ==
string.Empty))
.ThenBy(t => t.second_id)
.ThenBy(t => t.first_id)
.Select(t => t.primary_key)
.Skip(pageSize * pageNumber)
.Take(pageSize)
.ToList();

filtering results with Entity Framework

another kinda newbie question I guess. I have EF setup and now I want to select some records based on a filter. I have SomeClass with 4 items (all strings to keep things simple, lets call them string1, string2, and so on). Now, in a post I send the filter in an instance of SomeClass, but maybe not all properties are filled in.
So you might end up with string1="something", string2="bla" and string4="bla2". So string 3 = null. Now, how do I setup the query? If i try something like:
var dataset = entities.mydatabase
.Where(x => x.string1 == someclass.string1 && x.string2 == someclass.string2 && x.string3 == someclass.string3 && x.string4 == someclass.string4)
.Select(x => new { x.string1, x.string2, x.string3, x.string4}).ToList();
... I get no results, because string3=null. I could do something with checking all parameters and see if they're set and create the query based on that, but there must be something more elegant than that.
Anyone?
Thanks!
Ronald
The following will return all rows where the someclass.string is null OR equals to x.string.
var dataset = entities.mydatabase
.Where(x => someclass.string1 == null || x.string1 == someclass.string1)
.Where(x => someclass.string2 == null || x.string2 == someclass.string2)
.Where(x => someclass.string3 == null || x.string3 == someclass.string3)
.Where(x => someclass.string4 == null || x.string4 == someclass.string4)
.Select(x => new { x.string1, x.string2, x.string3, x.string4}).ToList();

Linq: Date less that x, but next record date is greater that x

I got records in database. Each record has field "Date".
For given date=x i need to find records that Date value is less that x, but next record date is greater of x.
Example:
id date
--------------
1 12.03.2013
2 15.03.2013
3 18.03.2013
now, I got X=16.03.2013, and i need a LINQ that return this record:
2 15.03.2013
BUT! for the X=15.03.2014 it should return nothing (because there is record with smaller date, but next record has exactly the same date as X)
How can i do this?
The simplest approach IMO is just to find the record that it would find, and check the date afterwards:
var result = db.Table
.Where(x => x.Date <= target.Date)
.OrderByDescending(x => x.Date)
.FirstOrDefault();
if (result != null && result.Date == target.Date)
{
result = null;
}
Or you could do it all in the query using a secondary Where clause after filtering to a single result:
var result = db.Table
.Where(x => x.Date <= target.Date)
.OrderByDescending(x => x.Date)
.Take(1)
.Where(x => x.Date != target.Date)
.FirstOrDefault();
Note that this doesn't work if all values are less than x (so there's no "next" record at all). I haven't yet worked out a way to handle that.
If all values can be less than x then you can use
var candidate = dates.Where(x => x.Date < target.Date)
.OrderByDescending(x => x.Date)
.FirstOrDefault();
var next = dates.Where(x => x.Date >= target.Date)
.OrderBy(x => x.Date)
.FirstOrDefault();
return (candite != null && next != null && next.Date != target.Date) ? candidate : null

Order by child record value(s) that can be empty

I've tried some combinations but I just don't understand how to do the following:
Lets say I have tables Requests and RequestActivities. I need to get all request sorted by RequestActivity.TimeOfCreation in descending order but RequestActivity may be null.
List<DA.GeneralRequest> ongoingGeneralRequests = db.GeneralRequests
.Where(t => t.GeneralRequestStatusID != 3 && (t.SupervisorID == currentUserId || t.CreatorID == currentUserId || t.AssignedUsers.Any(au => au.UserID == currentUserId)))
.OrderByDescending(x => x.GeneralRequestActivities.OrderBy(ga => ga.GeneralRequestActivityDate).Last().GeneralRequestActivityDate) //gives exeption
.ThenBy(a => a.Deadline).ToList();
I'm not really familiar with LINQ-To-SQL but doesn't work MAX in this case?
.OrderByDescending(x => x.GeneralRequestActivities
.Max(ga => ga.GeneralRequestActivityDate))
.ThenBy(a => a.Deadline)
.ToList();
You need to first cache the ordering value, and then order by the date if it is not null, else by some default date you want:
List<DA.GeneralRequest> ongoingGeneralRequests = db.GeneralRequests
.Where(t => t.GeneralRequestStatusID != 3 && (t.SupervisorID == currentUserId || t.CreatorID == currentUserId || t.AssignedUsers.Any(au => au.UserID == currentUserId)))
.Select(x => new {
Value = x,
OrderByValue = x.GeneralRequestActivities
.OrderBy(ga => ga.GeneralRequestActivityDate)
.LastOrDefault()) // cache value
.OrderByDescending(x => x.OrderByValue != null ?
OrderByValue.GeneralRequestActivityDate
: some default value)
.ThenBy(a => a.Value.Deadline)
.Select(a => a.Value)
.ToList();
Note that you can't use Last() extension method on empty IEnumerable. This is why you get the exception:
InvalidOperationException : The source sequence is empty.
In this line:
x.GeneralRequestActivities.OrderBy(ga => ga.GeneralRequestActivityDate).Last()
x.GeneralRequestActivities is empty, so calling Last() on it result on the exception.
Instead, use the LastOrDefault() extension method, which return null if the IEnumerable is empty.
Return Value Type: TSource default (TSource) if the source sequence is
empty; otherwise, the last element in the IEnumerable.

Categories

Resources