Where clause in Linq efficiency? - linq

The beginning of my Linq query is below.
Pay attention only to the where clause. Does Linq do the ToLower() only once? Or does it do ToLower() for every element of searchWords?
var products = from d in xElem.Descendants(fileName)
where searchWords.All(t => d.Element(productName).Value.ToLower().Contains(t))

Assuming this is LINQ to Objects, it will absolutely do it (and indeed the Element call) on each element of searchWords. There's nowhere it could really store state to do anything else, implicitly. You can optimize this easily yourself though:
var products = from d in xElem.Descendants(fileName)
let lowerD = d.Element(productName).Value.ToLower()
where searchWords.All(t => lowerD.Contains(t))
Or in a non-query expression you could use a statement lambda:
var products = xElem.Descendants(fileName)
.Where(d => {
string lowerD = d.Element(productName).Value.ToLower();
return searchWords.All(t => lowerD.Contains(t));
})
... // rest of query
Note that there are other ways of performing case-insensitive comparisons which are more robust. For example:
var products = from d in xElem.Descendants(fileName)
let v = d.Element(productName).Value
where searchWords.All(t =>
v.IndexOf(t, StringComparison.CurrentCultureIgnoreCase) != -1)

Related

how to get the linq list having Ids from IEnumerable<Object>

The code below userModel.Carriers is the type of IEnumerable<CarrierModel>.
userModel.Carriers has a list of carriers having Ids. With those Ids, I want to get CarrierDivision usign linq. But, I can't get it right because linq sqlexpression is not compatible with IEnumerable expression.
userModel.Carriers = carriersForRegion.Select(carrier => Mapper.Map<CarrierModel>(carrier))
.ToList();
var carrierDivision = from c in db.CarrierDivision where c.Contains();
collection.Contains will generate .. WHERE CarrierId IN (1, 2, 3) sql query
var carrierIds = userModel.Carriers.Select(carrier => carrier.Id).ToArray();
var divisions = db.CarrierDivision
.Where(division => carrierIds.Contains(division.CarrierId))
.ToArray();
In case db.CarrierDivision returns IEnumerable(not database), then I would suggest to create HashSet of carrier ids.
var carrierIds = userModel.Carriers.Select(carrier => carrier.Id).ToHashSet();
var divisions = db.CarrierDivision
.Where(division => carrierIds.Contains(division.CarrierId))
.ToArray();
With HashSet search executed without extra enumerations - O(1)

How to create programmatically single LINQ query w/ OR between Where() clauses (.Where(fn) OR .Where(fn) OR .Where(fn)) programatically

I'd like to know it is it possible to create programmatically single LINQ query (for EntityFramework 6) with N .Where() clauses, but with OR between these .Where() clauses.
Imagine IQueryable object defined like:
var query = dbContext.MyTable.Where(mt => mt.TimeStamp >= DateBegin);
What I need else is add N (unknown number) of Where clauses, but with OR condition between them.
Image list of some object:
List<MyObject> myObj =
new List<MyObject>({new MyObject {val = "a" }, new MyObject { val = "b"}}); //In real code there is more than 1 property.
then I'd like to add Where() clauses to query like:
myObj.ForEach(mo =>{
// THIS CREATES -AND- BETWEEN WHERE CLAUSES, BUT I NEED -OR-
query.Where(q=>q.MyValue == mo.val); // In real code there is more than 1 property to compare
});
I was thinking about .Union() beteween queries, but It could generate union between separated queries and it's not optimal I think.
Thanks!
Here's the solution: linq-to-entities-combining-predicates
Or course is necessary to use "latest" answer:
Copy/Paste class ParameterRebinder
Copy/Paste static class Utility
Usage:
Expression<Func<Car, bool>> theCarIsRed = c => c.Color == "Red";
Expression<Func<Car, bool>> theCarIsCheap = c => c.Price < 10.0;
Expression<Func<Car, bool>> theCarIsRedOrCheap = theCarIsRed.Or(theCarIsCheap);
var query = carQuery.Where(theCarIsRedOrCheap);
Because in my solution is N of expressions, I take first expression and then append other expressions in ForEach cycle.
var firstExpression = expressionList.First();
expressionList.Skip(1).ToList().ForEach(ex => { firstExpression = firstExpression.Or(ex); });

linq query with dynamic predicates in where clause joined by OR

you can easily create dynamic queries in c# if you add more restrictions to the current query.
var list = new List<Item>();
var q = list.AsQueryable();
q = q.Where(x => x.Size == 3);
q = q.Where(x => x.Color == "blue");
In this case, every new predicate is added performing an AND operation with the previous. The previous result is equivalent to:
q = list.Where(x => x.Size == 3 && x.Color == "blue");
Is it possible to achieve the same result but with OR instead of AND?
q = list.Where(x => x.Size == 3 || x.Color == "blue");
The idea is to have a variable number of expressions that are joined with OR operator.
Expected result would need to be written in some how similar to the following pseudo code:
var conditions = new List<Func<Item, bool>>();
And later iterate conditions to build something like:
foreach(var condition in conditions)
finalExpression += finalExpression || condition;
Another possible solution to this, especially when someone doesn't want to use an external library is using expression trees.
Add a following expression extension:
public static Expression<Func<T, bool>> Or<T>(
this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters);
return Expression.Lambda<Func<T, bool>>(
Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
}
As an example imagine you have a Container entity, which has InnerContainer nested entity with two properties Name and Id. Then you can use it in the following way:
Expression<Func<Container, bool>> whereQuery = c => c.InnerContainer.Name == "Name1";
whereQuery = whereQuery.Or(c => c.InnerContainer.Name == "Name2");
whereQuery = whereQuery.Or(c => c.InnerContainer.Id == 0);
var result = query
.Where(whereQuery)
.ToList();
Materializing such query will result in the following SQL:
SELECT [x].[Id], [x].[InnerContainerId]
FROM [Containers] AS [x]
LEFT JOIN [InnerContainer] AS [x.InnerContainer] ON [x].[InnerContainerId] = [x.InnerContainer].[Id]
WHERE [x.InnerContainer].[Name] IN (N'Name1', N'Name2') OR ([x].[InnerContainerId] = 0)
This way you can hold lambdas in a collection and loop through them.
Thanks to Raphaƫl Althaus that gave the following link:
http://www.albahari.com/nutshell/predicatebuilder.aspx
Predicate builder is the solution. You can use it installing LinqKit from Nuget. In that url you can find also the implementation of this class.
Note: in order to make this work with LinqToSql or LinqToEntities the IQueriable Object must be transformed using "AsExpandable()" method, for memory objects it's not required

EntityFramework: Add Where clause to ObjectSet Query to Select on CHILD attributes

The goal is to return a list of PARENT entities, based on attributes of their CHILD ENTITIES
eg Find me all the CASTLES where LADIES_IN_WAITING belong to PRINCESS 'X'
I want to do something like this:
var query = ObjectSet.Include(c => c.LADIES_IN_WAITING);
query = query.Where(p => p.REGION.ToLower().Contains("shrekVille"));
query = query.Where(p => p.LADIES_IN_WAITING.Where(c => c.PRINCESS.Equals("fiona")));
var results = query.ToList();
This is obviously the incorrect syntax but i can't find any clear examples of how to structure the Query.
I am currently resorting to something like this:
var query = ObjectSet.Include(c => c.LADIES_IN_WAITING);
query = query.Where(p => p.REGION.ToLower().Contains("shrekVille"));
// Get the results from the DB using the query built thus far
var results = query.ToList();
// Now filter the list in memory manually
foreach (var castle in results)
{
var matchingParents = new List<CASTLE>();
var matchingChildren = castle.LADIES_IN_WAITING.Where(a => a.PRINCESS.Equals("fiona"));
if (matchingChildren.Count() > 0)
matchingParents.Add(matchingChild);
}
results = matchingParents;
Any suggestions on how to correctly build the Query would be most welcomed!
You probably want to use the Any operator. It returns true if one item in a collection (i.e. 'any' of them) satisfies the predicate.
var query = ObjectSet.Include(c => c.LADIES_IN_WAITING);
query = query.Where(p => p.REGION.ToLower().Contains("shrekVille"));
// filter the query where, for each p,
// any of the LADIES_IN_WAITING have PRINCESS.Equals("fiona") == true
query = query.Where(p => p.LADIES_IN_WAITING.Any(c =>
c.PRINCESS.Equals("fiona"))); var results = query.ToList();
The complementary operator is All, which would filter your query to those results that have all the LADIES_IN_WAITING meeting the PRINCESS.Equals("fiona") criteria.

Groupby and where clause in Linq

I am a newbie to Linq. I am trying to write a linq query to get a min value from a set of records. I need to use groupby, where , select and min function in the same query but i am having issues when using group by clause. here is the query I wrote
var data =newTrips.groupby (x => x.TripPath.TripPathLink.Link.Road.Name)
.Where(x => x.TripPath.PathNumber == pathnum)
.Select(x => x.TripPath.TripPathLink.Link.Speed).Min();
I am not able to use group by and where together it keeps giving error .
My query should
Select all the values.
filter it through the where clause (pathnum).
Groupby the road Name
finally get the min value.
can some one tell me what i am doing wrong and how to achieve the desired result.
Thanks,
Pawan
It's a little tricky not knowing the relationships between the data, but I think (without trying it) that this should give you want you want -- the minimum speed per road by name. Note that it will result in a collection of anonymous objects with Name and Speed properties.
var data = newTrips.Where(x => x.TripPath.PathNumber == pathnum)
.Select(x => x.TripPath.TripPathLink.Link)
.GroupBy(x => x.Road.Name)
.Select(g => new { Name = g.Key, Speed = g.Min(l => l.Speed) } );
Since I think you want the Trip which has the minimum speed, rather than the speed, and I'm assuming a different data structure, I'll add to tvanfosson's answer:
var pathnum = 1;
var trips = from trip in newTrips
where trip.TripPath.PathNumber == pathnum
group trip by trip.TripPath.TripPathLink.Link.Road.Name into g
let minSpeed = g.Min(t => t.TripPath.TripPathLink.Link.Speed)
select new {
Name = g.Key,
Trip = g.Single(t => t.TripPath.TripPathLink.Link.Speed == minSpeed) };
foreach (var t in trips)
{
Console.WriteLine("Name = {0}, TripId = {1}", t.Name, t.Trip.TripId);
}

Resources