Sorting with Nulls Last - c#

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)

Related

LINQ order by and then by

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();

Add a if statement condition to a Linq statement

I am wanting a nice clean approach to adding in a conditional to an existing linq statement . I have a NEW variable personContactRoleId which will be zero or not zero.
context.PersonContactRoles
.Where(pcr => pcr.PersonId == personId);
.ToList()
.ForEach(pcr =>
{
// a lot of code
}
I was able to solve it with the iqueryable deferment of execution using an if statement, but it seems rather ugly and possibly less performant? Anything better to use?
var query = context.PersonContactRoles
.Where(pcr => pcr.PersonId == personId);
if(personContactRoleId != 0)
{
query = query.Where(b => b.PersonContactRoleId == personContactRoleId);
}
var results = query.ToList();
results.ForEach(pcr =>
{
// a lot of code
}
Again, this works, but looking for a cleaner way of doing this
The solution you have is fine, but if you want to put it all into one query without an if, you can add an additional Where condition that returns records where either personContactRoleId == 0 or prc.PersonContactRoleId == personContactRoleId is true:
context.PersonContactRoles
.Where(pcr =>
pcr.PersonId == personId &&
(personContactRoleId == 0 || pcr.PersonContactRoleId == personContactRoleId))
.ToList()
.ForEach(pcr =>
{
// a lot of code
});
This works without a need for an if block that checks that personContactRoleId is not 0
var query = context.PersonContactRoles
.Where(pcr => pcr.PersonId == personId).Where(b => {
return b.PersonContactRoleId == personContactRoleId && personContactRoleId != 0
}).ToList().ForEach(pcr =>
{
// a lot of code
}

multiple where in linq based on parameters value [duplicate]

This question already has answers here:
Linq to SQL multiple conditional where clauses
(3 answers)
Closed 7 years ago.
I want to have multiple where clauses in linq but out of them only one should execute, i was trying something like this:
public JsonResult GetPost(int? id, int? tagid, DateTime? date)
{
var ret = from data in db.Posts.Include(x => x.Tags)
.Include(x => x.Neighbourhood)
.Where((x => x.NeighbourhoodId == id) || (y => y.PostedDate == date) || third condition).ToList()
but i was unable to put second and third condition there becoz after putting dot after y, i cant see any options.
Now, out of these three, only one parameter would have value and other two would have null so, it should checks for parameter only with value.
should i write query like this, is it correct way:
if (id != null)
{
//whole query here
}
else if (tagid != null)
{
//whole query here
}
else (date != null)
{
//whole query here
}
Is it the best way to do this or something else is possible. many many thnks in advance for any suggestion.
Something like this?
var ret = from data in db.Posts.Include(x => x.Tags)
.Include(x => x.Neighbourhood)
.Where(x => x.NeighbourhoodId == (id ?? x.NeighbourhoodId) &&
x.<condition> == (tagid ?? x.<condition>) &&
x.PostedDate == (date ?? x.PostedDate).ToList();
Or like this:
var ret = from data in db.Posts.Include(x => x.Tags)
.Include(x => x.Neighbourhood)
.Where(x => id.HasValue ? x.NeighbourhoodId == id :
tagid.HasValue ? x.<condition> == tagid :
x.PostedDate == date).ToList();
Another option is to build your query more dynamically. I think this also makes your code more human readable, and your conditions can be more complex if needed (for example, build your query inside a loop or something). And you can use this with any other operator, like Include etc. Once your query is built, you can call ToList().
var ret = db.Posts.Include(x => x.Tags).Include(x => x.Neighbourhood);
if (id != null)
{
ret = ret.Where((x => x.NeighbourhoodId == id);
}
else
{
...
}
var result = ret.ToList();
You could use the following:
var ret = from data in db.Posts.Include(x => x.Tags)
.Include(x => x.Neighbourhood)
.Where(x => id == null || x.NeighbourhoodId == id)
.Where(x => date == null || y.PostedDate == date)
.ToList();
If the paramter is null, the where-clauses returns every element of the sequence. If its not null it only returns the elements which matches.

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();

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