How to query a nested list using a lambda expression - linq

In my repository implementation I can run the following query using a lambda expression:
public IList<User> GetUsersFromCountry(string)
{
return _UserRepository.Where(x => x.Country == "Sweden").ToList();
}
So far so good, simple stuff. However, I'm having difficulties to write a lambda expression against a nested -> nested list. Given the following example (sorry couldn't think of a better one):
The following query works absolutely fine and returns all clubs, which have members over the age of 45
public IList<Clubs> GetGoldMembers()
{
var clubs = from c in ClubRepository
from m in c.Memberships
where m.User.Age > 45
select c;
return clubs;
}
At the moment, this is where my knowledge of lambda expression ends.
How could I write the above query against the ClubRepository, using a lambda expression, similar to the example above?

This might work (untested)...
var clubs = ClubRepository.Where(c=>c.MemberShips.Any(m=>m.User.Age > 45));

Here's one way to do it:
var clubs = clubRepository
.SelectMany(c => c.Memberships, (c, m) => new { c, m })
.Where(x => x.m.User.Age > 45)
.Select(x => x.c);

A more generic way
List<T> list= new List<T>();
list= object1.NestedList1.SelectMany(x => x.NestedList2).ToList();
Where NestedList2 matches the data type of "list"

Related

How can I use hashset to get unique values from an entity?

I'm trying to remove the repeated course from the linq query below. When this query returns it returns multiples of the same course(s) but I would like for it to return unique courses. Can I use a hashset to make this list unique? Thanks for any help!
foreach (var course in Model.Assignments
.Select((x, y) => new { Data = x, Index = y })
.Where(x => x.Data.Ids == listOfIds[i]))
{
// code here
}
I'm not sure that understand you in 100 percent, but if you have any class you can override methods: Equals and GetHashCode, then you can use Distinct() for query.
look here

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

Linq - Retrieve first list after SelectMany

I've an object list where each object contains an internal object list and what I would fetching is the father list (left list), however I'm forced to use SelectMany function..Is it possibile?
Naive Example:
var query = objList.SelectMany(p => p.InternalList)
.Where(internalObj => internalObj.SomeProprerty == true)
.SELECT(objList);
Is there any way to accomplish this?
Assuming you don't actually want objList, but instead the element of objList which we're looking at at the time, I think you just want:
var query = objList.SelectMany(p => p.InternalList, (o, p) => new { o, p })
.Where(pair => pair.p.SomeProperty)
.Select(pair => pair.o);
If that's not what you're after, it would really help if you'd give a concrete example.
EDIT: If you only want any example from objList where any element of the internal list has a SomeProperty value of true, you can do that more easily like this:
var value = objList.FirstOrDefault(o => o.InternalList.Any(p => p.SomeProperty));
if (value != null)
{
...
}

LINQ for LIKE queries of array elements

Let's say I have an array, and I want to do a LINQ query against a varchar that returns any records that have an element of the array anywhere in the varchar.
Something like this would be sweet.
string[] industries = { "airline", "railroad" }
var query = from c in contacts where c.industry.LikeAnyElement(industries) select c
Any ideas?
This is actually an example I use in my "Express Yourself" presentation, for something that is hard to do in regular LINQ; As far as I know, the easiest way to do this is by writing the predicate manually. I use the example below (note it would work equally for StartsWith etc):
using (var ctx = new NorthwindDataContext())
{
ctx.Log = Console.Out;
var data = ctx.Customers.WhereTrueForAny(
s => cust => cust.CompanyName.Contains(s),
"a", "de", "s").ToArray();
}
// ...
public static class QueryableExt
{
public static IQueryable<TSource> WhereTrueForAny<TSource, TValue>(
this IQueryable<TSource> source,
Func<TValue, Expression<Func<TSource, bool>>> selector,
params TValue[] values)
{
return source.Where(BuildTrueForAny(selector, values));
}
public static Expression<Func<TSource, bool>> BuildTrueForAny<TSource, TValue>(
Func<TValue, Expression<Func<TSource, bool>>> selector,
params TValue[] values)
{
if (selector == null) throw new ArgumentNullException("selector");
if (values == null) throw new ArgumentNullException("values");
if (values.Length == 0) return x => true;
if (values.Length == 1) return selector(values[0]);
var param = Expression.Parameter(typeof(TSource), "x");
Expression body = Expression.Invoke(selector(values[0]), param);
for (int i = 1; i < values.Length; i++)
{
body = Expression.OrElse(body,
Expression.Invoke(selector(values[i]), param));
}
return Expression.Lambda<Func<TSource, bool>>(body, param);
}
}
from c in contracts
where industries.Any(i => i == c.industry)
select c;
something like that. use the any method on the collection.
IEnumerable.Contains() translates to SQL IN as in:
WHERE 'american airlines' IN ('airline', 'railroad') -- FALSE
String.Contains() which translates to SQL LIKE %...% as in:
WHERE 'american airlines' LIKE '%airline%' -- TRUE
If you want the contacts where the contact's industry is LIKE (contains) any of the given industries, you want to combine both Any() and String.Contains() into something like this:
string[] industries = { "airline", "railroad" };
var query = from c in contacts
where industries.Any(i => c.Industry.Contains(i))
select c;
However, combining both Any() and String.Contains() like this is NOT supported in LINQ to SQL. If the set of given industries is small, you can try something like:
where c.Industry.Contains("airline") ||
c.Industry.Contains("railroad") || ...
Or (although normally not recommended) if the set of contacts is small enough, you could bring them all from the DB and apply the filter with LINQ to Objects by using contacts.AsEnumerable() or contacts.ToList() as the source of the query above:
var query = from c in contacts.AsEnumerable()
where industries.Any(i => c.Industry.Contains(i))
select c;
it will work if you build up the query as follows:
var query = from c in contacts.AsEnumerable()
select c;
query = query.Where(c=> (c.Industry.Contains("airline")) || (c.Industry.Contains("railroad")));
you just need to programmatically generate the string above if the parameters airline and railroad are user inputs. This was in fact a little more complicated than I was expecting. See article - http://www.albahari.com/nutshell/predicatebuilder.aspx
Unfortunately, LIKE is not supported in LINQ to SQL as per here:
http://msdn.microsoft.com/en-us/library/bb882677.aspx
To get around this, you will have to write a stored procedure which will accept the parameters you want to use in the like statement(s) and then call that from LINQ to SQL.
It should be noted that a few of the answers suggest using Contains. This won't work because it looks to see that the entire string matches the array element. What is being looked for is for the array element to be contained in the field itself, something like:
industry LIKE '%<element>%'
As Clark has mentioned in a comment, you could use a call to IndexOf on each element (which should translate to a SQL call):
string[] industries = { "airline", "railroad" }
var query =
from c in contacts
where
c.industry.IndexOf(industries[0]) != -1 ||
c.industry.IndexOf(industries[1]) != -1
If you know the length of the array and the number of elements, then you could hard-code this. If you don't, then you will have to create the Expression instance based on the array and the field you are looking at.

Resources