How to write an "OR" within a Linq to Sql .Where() - c#

I want to get all records WHERE (s.override == 1 OR (s.override == 2 AND s.approved == 1))
How can I do that using the .Where x.subcontracts.Where(s ==> ??)

Use standard C# binary operators:
x.subcontracts
.Where(s => s.override == 1 || (s.override == 2 && s.approved == 1))

Here is the where clause you need:
x.subcontracts.Where(s => (s.override == 1) || (s.override == 2 && s.approved == 1))

Related

Troubles with Filtering

My Filter is problematic. My goal is to have the datagrid on load show any with a created person where date > Today's day - 1 month.
I have some filters surname, forename. I want to Display any Person that had some activities within last 3 months. Thats found through this query
(ctx.Interactions.Where(z => z.Attendees.Where(w => w.Person_Id == x.Id).Any() && z.ActivityDate >= recent ).Any())
The issue I'm having is when surname or forename is filled, I want the query to ignore the created date prequisite and the Interaction Prerequisite.
Items.AddRange(ctx.People.
Where(x => (
((Surname.Length == 0) && (Forename.Length == 0)) ?
(x.Created > limit) : true &&
(((Surname.Length == 0) || x.Surname.StartsWith(Surname)) &&
((Forename.Length == 0) || x.Forename.StartsWith(Forename)) &&
(ctx.Interactions.Where(z => z.Attendees.Where(w => w.Person_Id == x.Id).Any() && z.ActivityDate >= recent ).Any())
One thing I did try was to move the Interaction query and had it with the x.created but that ruined the runtime. Currently it runs around 15seconds, with that change it takes about 2 mins. Any tips or suggestions would be great.
recent is today's date - 3 months
You can split the filtering expression:
var filteredPeople = ctx.People; // here var should be replaced with IEnumerable<T> where T is the type of items in People
if (string.IsNullOrEmpty(Surname) && string.IsNullOrEmpty(Forename))
filteredPeople = filteredPeople.Where(x => x.Created > limit);
else
{
if (!string.IsNullOrEmpty(Surname))
filteredPeople = filteredPeople.Where(x => x.Surname.StartsWith(Surname));
if (!string.IsNullOrEmpty(Forename))
filteredPeople = filteredPeople.Where(x => x.Forename.StartsWith(Forename));
filteredPeople = filteredPeople.Where(x => ctx.Interactions.Where(z => z.ActivityDate >= recent)
.Any(z => z.Attendees.Any(w => w.Person_id == p.Id)));
}
Items.AddRange(filteredPeople);
I think your issue may be in the use of your conditional operator. The conditional operator takes the ? and : clauses completely independently. So what you're currently telling it is,
If Surname and Forename are length 0
Then return ALL where x.Created > limit
Else
Then apply all other filters.
I've reworked the query a bit. This should improve performance because it will be retrieving fewer (and more accurate) results.
Items.AddRange(ctx.People.
Where(x => (
((Surname.Length == 0 && Forename.Length == 0) ? x.Created > limit : true)
&&
(
(Surname.Length == 0 || x.Surname.StartsWith(Surname))
&& (Forename.Length == 0 || x.Forename.StartsWith(Forename))
&& (ctx.Interactions.Any(z => z.Attendees.Any(w => w.Person_Id == x.Id) && z.ActivityDate >= recent))
)
Here's another version that doesn't hit the ctx twice, and instead traverses from Person > Attendee > Interaction instead of backwards. This might affect the performance as well:
Items.AddRange(ctx.People.
Where(x => (
((Surname.Length == 0 && Forename.Length == 0) ? x.Created > limit : true)
&&
(
(Surname.Length == 0 || x.Surname.StartsWith(Surname))
&& (Forename.Length == 0 || x.Forename.StartsWith(Forename))
&& x.Attendees.Any(attendee => attendee.Interactions.Any(interaction => interaction.ActivityDate >= recent))
)

Skip part of query if item text is empty

I have a query
return uow.CustomerRepo
.Get()
.Where
(
c=>
c.Firstname.StartsWith(customerSearch.Initial) &&
c.Surname == customerSearch.Surname &&
c.Email == customerSearch.Email &&
c.Postcode == customerSearch.PostCode
)
Is there a way to skip parts of the query if something in customerSearch is empty?
so I want to skip the part
c.Surname == customerSearch.Surname
if
customerSearch.Surname
Is empty
You can do it with a condition that checks the customerSearch part explicitly:
.Where
(
c=>
(customerSearch.Initial == null || c.Firstname.StartsWith(customerSearch.Initial)) &&
(customerSearch.Surname == null || c.Surname == customerSearch.Surname) &&
(customerSearch.Email == null || c.Email == customerSearch.Email) &&
(customerSearch.PostCode == null || c.Postcode == customerSearch.PostCode)
)
If you need to check for empty strings rather than null, change the condition accordingly.

Compare complex subquery between two values

I have repository with students and I want to get some students who have grades count in between 0 and 2.
This is my code:
_unitOfWork.Repository<Student>().Get(o => o.OrganizationId == organizationId
&& o.Grades.Where( o1 => o1.LastVersion
&& o1.Type == 5
&& o1.Value == 1).Count() > 0
&& o.Grades.Where( o1 => o1.LastVersion
&& o1.Type == 5
&& o1.Value == 1).Count() <= 2 );
This code is working, but my question is how to change this query with less code.
Is there any way to replace Count with some variable and not use it two times in query?
something like this?
var values = Enumerable.Range(1, 2);
_unitOfWork.Repository<Student>().Get(o => o.OrganizationId == organizationId
&& values.Contains(
o.Grades.Where( o1 => o1.LastVersion
&& o1.Type == 5
&& o1.Value == 1).Count()
));

Or Condition in Entity Framework

I am working on entity framework project, i have to apply Or condition in dbContext.Where
I have tried this but its giving me error "Operator || cannot be applied to operand of types lambda expressions"
return dataContext.Friends
.Where((r => r.ToUserId == touserid && r.FromUserId == fromuserid)
|| (r => r.ToUserId == fromuserid&& r.FromUserId == touserid ))
.ToList();
I also tried using && instead of || but its giving me same error for &&,how can i apply Or condition for this senario?
I have tried without brackets as well
You need to do it like this:
return dataContext.Friends.Where(r => (r.ToUserId == touserid && r.FromUserId == fromuserid) || (r.ToUserId == fromuserid && r.FromUserId == touserid))
.ToList();
The only difference is that I deleted the second r => and fixed the parenthesis.
Put it into one lambda that includes the || instead of ||ing two separate lambas:
return dataContext.Friends.Where(r => (r.ToUserId == touserid && r.FromUserId == fromuserid) || (r.ToUserId == fromuserid&& r.FromUserId == touserid)).ToList();
#Syed
|| (r => r.ToUserId == fromuserid&& r.FromUserId == touserid )).ToList();
Should be
|| (r => r.ToUserId == fromuserid && r.FromUserId == touserid )).ToList();
note the space between the "fromuserid&&".

C# Lambda Problem

Probably something simple, but as I'm new to lambda expressions, the problem evades me:
m => m.contactID == contactID && m.primaryAddress == true && (m.addressTypeID == 2 || m.addressTypeID == 3)
I tried to use that lambda expression but I receive an invalid operator. Is there a way to simplify this so that it would work?
Edit:
The equivolent sql query would be:
SELECT *
FROM Contact
WHERE contactID = 3
AND primaryAddress = 1
AND (addressTypeID = 2 OR addressTypeID = 3)
I have a repository function defined like so:
public E Single(Expression<Func<E, bool>> where)
{
return objectSet.Single<E>(where);
}
I'm passing the lambda expression above into this function:
myRepository.Single(m => m.contactID == contactID && m.primaryAddress == true && (m.addressTypeID == 2 || m.addressTypeID == 3));
If you are receiving an InvalidOperationException, the most likely cause is that there is more than one record that matches your criteria.
Queryable.Single will raise InvalidOperationException if there is more than a single correct value. In this case, try using .First(m => ..) instead:
myRepository.First(m =>
m.contactID == contactID &&
m.primaryAddress == true &&
(m.addressTypeID == 2 || m.addressTypeID == 3)
);
This will return the first matching result, if there are more than one. If you need to handle no matches, look into FirstOrDefault (which will return null if there are no matches).
m.primaryAddress == true looks suspicious. is m.primaryAddress really a bool property?
m => (m.contactID == contactID && m.primaryAddress == true && (m.addressTypeID == 2 || m.addressTypeID == 3)) is merely a boolean expression.
You need to do something like
list.Remove(m => (m.contactID == contactID && m.primaryAddress == true && (m.addressTypeID == 2 || m.addressTypeID == 3))) etc
This says take each item in my list as m if this returns true remove m
Edit OP reposted while I was writing that answer
I would write this like this as to your syntax.
Func Filter<var, bool> = m => (m.contactID == contactID && m.primaryAddress == true && (m.addressTypeID == 2 || m.addressTypeID == 3))
then pass Filter into your myrepository.Single(Filter)
From your SQL query, should it be:
m => m.contactID == contactID && m.primaryAddress == 1 && (m.addressTypeID == 2 || m.addressTypeID == 3)

Categories