Combine linq queries together - c#

I have to linq queries which have only a small difference between them. I am trying to merge them both.
.Where(i =>
!i.Username.StartsWith("e-") &&
i.SSN != null && i.SSN != "" &&
i.DisplayName != null && i.DisplayName != "" &&
i.LastName != null && i.LastName != "" &&
i.FirstName != null && i.FirstName != "")
.ToList();
and the other one is
.Where(i =>
!i.Username.StartsWith("e-") &&
i.SSN != null && i.SSN != "" &&
i.DisplayName != null && i.DisplayName != "" &&
i.LastName != null && i.LastName != "" &&
i.FirstName != null && i.FirstName != "" &&
i.WhenChanged.HasValue && i.WhenChanged.Value > DateTime.UtcNow.Add(_whenChangedTimeSpan))
.ToList();
as you can see only the last item in where clause is different. Can they both be merge together?

If you choice of either of the Linq Queries is based on a "condition", you could do the following.
var result = list.Where(
i => !i.Username.StartsWith("e-")
&& i.SSN != null && i.SSN != ""
&& i.DisplayName != null && i.DisplayName != ""
&& i.LastName != null && i.LastName != ""
&& i.FirstName != null && i.FirstName != ""
&& (condition?
i.WhenChanged.HasValue && i.WhenChanged.Value > DateTime.UtcNow.Add(_whenChangedTimeSpan)
: true)).ToList();

Since the second query is just a subset of the first query, first execute the first query and then run the filter over that result:
var result = (...).Where(
i => !i.Username.StartsWith("e-")
&& i.SSN != null && i.SSN != ""
&& i.DisplayName != null && i.DisplayName != ""
&& i.LastName != null && i.LastName != ""
&& i.FirstName != null && i.FirstName != ""
).ToList();
var filteredResult = result.Where(i.WhenChanged.HasValue && i.WhenChanged.Value > DateTime.UtcNow.Add(_whenChangedTimeSpan)).ToList();
This will run the query only once on the database, and will do the second part in memory on your app server.

Maybe you are looking for something like this.
Create a method to do the common check
bool CommonCheck(TypeOfYourVariable i)
{
return !i.Username.StartsWith("e-") &&
i.SSN != null && i.SSN != "" &&
i.DisplayName != null && i.DisplayName != "" &&
i.LastName != null && i.LastName != "" &&
i.FirstName != null && i.FirstName != "";
}
Use it like this:
// first
.Where(i => CommonCheck(i))
.ToList();
// secpmd
.Where(i => CommonCheck(i) &&
i.WhenChanged.HasValue && i.WhenChanged.Value > DateTime.UtcNow.Add(_whenChangedTimeSpan))
.ToList();
Update, or you can do this:
var firstQueryResult = yourInput.Where(i =>
!i.Username.StartsWith("e-") &&
i.SSN != null && i.SSN != "" &&
i.DisplayName != null && i.DisplayName != "" &&
i.LastName != null && i.LastName != "" &&
i.FirstName != null && i.FirstName != "" &&
).ToList();
var secondQueryResult = firstQueryResult
.Where(i=> i.WhenChanged.HasValue && i.WhenChanged.Value > DateTime.UtcNow.Add(_whenChangedTimeSpan))
.ToList();

Related

Variable amount of OR, AND conditions on a lambda WHERE clause

I have looked at similar questions but none have really been able to answer my question.
All I want to do is make a select using lambda but the trick is, there is a variable amount of OR/AND conditions for the selection. My function receives a list of AND conditions and it should select based on that.
Here is what I have right now and it supports up to 10 AND conditions passed as a string to compare, but this code is terrible.. in reality it should be able to accept an undefined/variable amount of conditions.
Not sure how to go about this..
ProductTags is a list of tags.. if the product has all of the tags then it is returned.
public static List<product> FilterProductsByTagsAll(List<string> tags)
{
List<product> products = new List<product>();
switch (tags.Count)
{
case 1:
products = Database.Products.Values.Where(i => i.ProductTags != null
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[0]).Any()).ToList();
break;
case 2:
products = Database.Products.Values.Where(i => i.ProductTags != null
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[0]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[1]).Any()).ToList();
break;
case 3:
products = Database.Products.Values.Where(i => i.ProductTags != null
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[0]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[1]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[2]).Any()).ToList();
break;
case 4:
products = Database.Products.Values.Where(i => i.ProductTags != null
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[0]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[1]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[2]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[3]).Any()).ToList();
break;
case 5:
products = Database.Products.Values.Where(i => i.ProductTags != null
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[0]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[1]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[2]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[3]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[4]).Any()).ToList();
break;
case 6:
products = Database.Products.Values.Where(i => i.ProductTags != null
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[0]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[1]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[2]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[3]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[4]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[5]).Any()).ToList();
break;
case 7:
products = Database.Products.Values.Where(i => i.ProductTags != null
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[0]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[1]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[2]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[3]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[4]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[5]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[6]).Any()).ToList();
break;
case 8:
products = Database.Products.Values.Where(i => i.ProductTags != null
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[0]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[1]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[2]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[3]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[4]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[5]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[6]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[7]).Any()).ToList();
break;
case 9:
products = Database.Products.Values.Where(i => i.ProductTags != null
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[0]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[1]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[2]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[3]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[4]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[5]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[6]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[7]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[8]).Any()).ToList();
break;
case 10:
products = Database.Products.Values.Where(i => i.ProductTags != null
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[0]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[1]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[2]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[3]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[4]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[5]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[6]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[7]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[8]).Any()
&& i.ProductTags.Where(i => i != null && i.Tag_name == tags[9]).Any()).ToList();
break;
default:
break;
}
return products;
}
Thank you for trying to help out.
Try this query:
var allTagsProds = Database.Products.Values.Where(p => p.ProductTags != null && p.ProductTags.Select(pt => pt.Tag_name).Intersect(tags).Count() == tags.Count());
For each product, it selects the product tag names then intersects them with the tags list. This produces a list of product tag names that match the tags list.
Then it compares the count of this list with the count of the tags list and if they are the same, the product has all the tags. These are then returned.
Example using hard coded models:
public class Tag {
public string Tag_name {get; set;}
}
public class Product {
public ICollection<Tag> ProductTags {get; set;}
public string Name {get; set;}
}
public class Program
{
public static void Main()
{
List<string> tags = new List<string> {"a","b","c","d","e","f"};
var prodTags = new List<Tag>() {
new Tag() {Tag_name = "a"},
new Tag() {Tag_name = "b"},
new Tag() {Tag_name = "c"},
new Tag() {Tag_name = "d"}
};
var prodTags2 = new List<Tag>() {
new Tag() {Tag_name = "a"},
new Tag() {Tag_name = "b"},
new Tag() {Tag_name = "c"},
new Tag() {Tag_name = "d"},
new Tag() {Tag_name = "e"},
new Tag() {Tag_name = "f"}
};
var products = new List<Product>() {
new Product() { Name="Prod1", ProductTags = prodTags },
new Product() { Name="Prod2",ProductTags = prodTags2 }
};
var allTagsProds = products.Where(p => p.ProductTags != null && p.ProductTags.Select(pt => pt.Tag_name).Intersect(tags).Count() == tags.Count());
foreach(var prod in allTagsProds)
{
//Writes "Prod2"
Console.WriteLine(prod.Name);
}
}
}

Variable has a null value but if statement still gets called

I have an if statement
if (materialtype != "WINDOWVINYLREPL"
|| materialtype != "ROOFING"
&& materialtype != "null"
&& materialtype != null)
{
subtype = (from a in UEF.MaterialSubTypes
where a.MaterialSubType1.Equals(subtype) && a.Code.Contains(materialtype)
select a.Code).FirstOrDefault();
}
and even though materialtype is equal to null the if statement still gets called and it shouldn't be
if (materialtype != "WINDOWVINYLREPL" || ...
the variable is null so certainly it's not equal to "WINDOWVINYLREPL", hence this condition is true and it goes in.
You have an OR || condition. It should be like :
if (materialtype != "WINDOWVINYLREPL" && materialtype != "ROOFING" && materialtype != "null" && materialtype != null)
{
subtype = (from a in UEF.MaterialSubTypes where a.MaterialSubType1.Equals(subtype) && a.Code.Contains(materialtype) select a.Code).FirstOrDefault();
}
Condition was not written with proper brackets. AND, OR conflicted
if ((materialtype != "WINDOWVINYLREPL") || (materialtype != "ROOFING" && materialtype != "null")) && materialtype != null)
{
subtype = (from a in UEF.MaterialSubTypes where a.MaterialSubType1.Equals(subtype) && a.Code.Contains(materialtype) select a.Code).FirstOrDefault();
}
Your condition is equivalent to:
if((materialtype != "WINDOWVINYLREPL") || (materialtype != "ROOFING" && materialtype != "null" && materialtype != null))
Which is true if materialtype == null, because (materialtype != "WINDOWVINYLREPL") is true.
The && operator has higher priority than ||
Try to use parentheses to separate logic "OR" and "And"
Because if the value is null the test is always true
if ((materialtype != "WINDOWVINYLREPL" || materialtype != "ROOFING")
&& materialtype != null)
{
.....
}

How can I write the following lambda expression in one line?

I want to fetch the records as follows
SearchResult.condition is null then fetch all the rows from Person
if SearchResult.condition is false then fetch the rows where PersonType column contains null value
if SearchResult.condition is true then fetch the rows where PersonType column contains non null value
struct SearchResult
{
public string Name;
public bool? condition;
}
Expression<Func<Person, bool>> expression;
if(condition==null)
{
expression= (a =>
(SearchResult.Name==null || a.Name == SearchResult.Name)
);
}
else if(condition.Value == true)
{
expression= (a =>
(SearchResult.Name==null || a.Name == SearchResult.Name)
&& a.PersonType != null)
}
else if(condition.Value == false)
{
expression= (a =>
(SearchResult.Name==null || a.Name == SearchResult.Name)
&& a.PersonType == null)
}
I want to write the expression in one expression instead of using if else conditions. Can u plz help me in it?
Well you can do it with a conditional operator, but you need to specify the type of the expression tree for each lambda expression:
var expression = condition == null
? (Expression<Func<Person, bool>>) a => SearchResult.Name == null ||
a.Name == SearchResult.Name
: condition.Value
? (Expression<Func<Person, bool>>) a => (SearchResult.Name == null ||
a.Name == SearchResult.Name) &&
a.PersonType != null
: (Expression<Func<Person, bool>>) a => (SearchResult.Name == null ||
a.Name == SearchResult.Name) &&
a.PersonType == null;
But assuming you're going to use this with a LINQ query, you'd be much better off with something like:
var query = foo.Where(a => SearchResult.Name == null ||
a.Name == SearchResult.Name);
if (condition != null)
{
query = condition.Value ? query.Where(a => a.PersonType != null)
: query.Where(a => a.PersonType == null);
}
As an aside, I'd strongly advise you to avoid writing mutable structs or using public fields.
You could shorten as:
expression = a =>
(SearchResult.Name == null || a.Name == SearchResult.Name) &&
(SearchResult.condition == null || Search.condition == (a.PersonType != null));

AND OR in a Linq Query

In a Linq query I need to filter appointments by Date and Local, Date or Local.
So if GivenDate and GivenLocal are not null I need to filter by GivenDate and GivenLocal:
appointments.Where(x => x.Date == x.GivenDate && x.Local == x.GivenLocal)
If GivenDate is null then the filter would be done by Local:
appointments.Where(x => x.Local == x.GivenLocal)
And if GivenLocal is null then filter by Date:
appointments.Where(x => x.Date == x.GivenDate)
Is it possible to do this with one query instead of using IF statements and 3 queries?
appointments.Where(x =>
(x.GivenDate == null || x.Date == x.GivenDate) &&
(x.GivenLocal == null || x.Local == x.GivenLocal) && )
appointments.Where(x => ((x.GivenDate != null && x.GivenLocal != null && x.Date == x.GivenDate && x.Local == x.GivenLocal) || (x.GivenDate == null && x.Local == x.GivenLocal ) || (x.GivenLocal == null && x.Date == x.GivenDate)))

EF Non-static method requires a target

I've serious problems with the following query.
context.CharacteristicMeasures
.FirstOrDefault(cm => cm.Charge == null &&
cm.Characteristic != null &&
cm.Characteristic.Id == c.Id &&
cm.Line != null &&
cm.Line.Id == newLine.Id &&
cm.ShiftIndex != null &&
cm.ShiftIndex.Id == actShiftIndex.Id &&
(newAreaItem == null ||
(cm.AreaItem != null &&
cm.AreaItem.Id == newAreaItem.Id)));
I get a TargetException: Non-static method requires a target when newAreaItem is null.
If newAreaItem is not null I get an NotSupportedException: Unable to create a constant value of type 'PQS.Model.AreaItem'. Only primitive types or enumeration types are supported in this context.
Things I've already checked if they're null:
c, newLine, actShiftIndex all 3 variables are not null and the Id is accessible.
I dont get it... please help.
If u need more information.. dont hesitate to ask...
UPDATE
I could eliminate the NotSupportedException, but I still got the TargetException when my newAreaItemIsNull is true.. :/
bool newAreaItemIsNull = (newAreaItem == null);
var mc = context.CharacteristicMeasures
.FirstOrDefault(cm => cm.Charge == null &&
cm.Characteristic != null &&
cm.Characteristic.Id == c.Id &&
cm.Line != null &&
cm.Line.Id == newLine.Id &&
cm.ShiftIndex != null &&
cm.ShiftIndex.Id == actShiftIndex.Id &&
(newAreaItemIsNull ||
(cm.AreaItem != null &&
cm.AreaItem.Id == newAreaItem.Id)));
UPDATE
I finally did it. It seems that the query parse can't parse my newAreaItem(IsNull) because it's not in the DB model somehow !?
I have to split my queries..
bool newAreaItemIsNull = (newAreaItem == null);
MeasureCharacteristic mc;
if (newAreaItemIsNull)
mc = context.CharacteristicMeasures
.FirstOrDefault(cm => cm.Charge == null &&
cm.Characteristic != null &&
cm.Characteristic.Id == c.Id &&
cm.Line != null &&
cm.Line.Id == newLine.Id &&
cm.ShiftIndex != null &&
cm.ShiftIndex.Id == actShiftIndex.Id);
else
mc = context.CharacteristicMeasures
.FirstOrDefault(cm => cm.Charge == null &&
cm.Characteristic != null &&
cm.Characteristic.Id == c.Id &&
cm.Line != null &&
cm.Line.Id == newLine.Id &&
cm.ShiftIndex != null &&
cm.ShiftIndex.Id == actShiftIndex.Id &&
cm.AreaItem != null &&
cm.AreaItem.Id == newAreaItem.Id);
Does someone know a better solution?
Try moving newAreaItem == null outside of the query
bool newAreaItemIsNull = (newAreaItem == null);
and replace newAreaItem == null with newAreaItemIsNull in query.
Query parser can only operate with the objects in the database, and newAreaItem is not one of them.
I had the exact same problem as you have when newAreaItem == null is true.
The problem comes from the fact that the item used in the LINQ cannot be null. Thus, when newAreaItem == null is true it means that newAreaItem is null and this leads to the error being thrown.
All you can do in my opinion is, after checking newAreaItem == null, to set the newAreaItem to a new empty object of that type if newAreaIteam is null. The newAreaItemIsNull condition will still be in place, thus the
(cm.AreaItem != null && cm.AreaItem.Id == newAreaItem.Id)
in your code below will still not be evaluated if newAreaItem is null.
context.CharacteristicMeasures.
FirstOrDefault(cm => cm.Charge == null &&
cm.Characteristic != null && cm.Characteristic.Id == c.Id &&
cm.Line != null && cm.Line.Id == newLine.Id &&
cm.ShiftIndex != null && cm.ShiftIndex.Id == actShiftIndex.Id &&
(newAreaItem == null ||
(cm.AreaItem != null && cm.AreaItem.Id == newAreaItem.Id)));

Categories

Resources