If I work with LINQ to Objects, I can use Func<TIn, TOut> in Select, like this:
Enumerable.Range(1, 10).Select(x => new { A = x, B = SomeFunc });
where SomeFunc is something like this:
Func<int, long> SomeFunc = x => x * x;
But working with LINQ to Entities, Func doesn't work, I must use Expression. And this code doesn't work:
var query = Enumerable.Range(1, 10)
.AsQueryable()
.Select(x => new { A = x, B = SomeExpr });
where SomeExpr is something like this:
Expression<Func<int, long>> SomeExpr = x => x * x;
How can I use Expressions in Select in query?
You have to compile and execute the query
var query2 = Enumerable.Range(1, 10)
.AsQueryable()
.Select(x => new { A = x, B = SomeExpr.Compile().DynamicInvoke(x) });
Problem is that x => new {...} is already the expression you pass as an argument to Select(...). Your code will work if you compile and invoke SomeExpr into the select expression.
Expression<Func<int, long>> SomeExpr = x => x * x;
var query = Enumerable.Range(1, 10)
.AsQueryable()
.Select(x => new { A = x, B = SomeExpr.Compile().Invoke(x) });
Related
How can I "translate" this SQL query to Linq Lambda Expression:
Select SC.[Description],
COUNT(C.[StatusID]) as Amount
From [StatusCandidate] SC
Left Join
(Select *
From [Candidate] AS c
Where c.RequestID = 1) AS C
ON C.StatusID = SC.StatusCandidateID
Group By SC.[Description];
I try it, But the result is not correct:
dbContext.StatusCandidates
.GroupJoin(
dbContext.Candidates.Where(u => u.RequestID == requestId),
x => x.StatusCandidateID,
y => y.StatusID,
(x, y) => new {x, y})
.GroupBy(g => new {g.x.Description})
.Select(z => new AmountStatus{
StatusName = z.Key.Description,
Amount = z.Count()
}).ToList();
You are pretty close to the desired result: your LINQ makes an inner join, while your SQL has an outer join.
dbContext.StatusCandidates
.GroupJoin(
dbContext.Candidates.Where(u => u.RequestID == requestId)
, x => x.StatusCandidateID
, y => y.StatusID
, (x, y) => new { StatusCandidate = x, StatusGroup = y }
)
.SelectMany(
x => x.StatusGroup.DefaultIfEmpty()
, (x, y) => new { x.StatusCandidate, Status = y}
)
.GroupBy(g => new { g.StatusCandidate.Description })
.Select(z => new AmountStatus{
StatusName = z.Key.Description
, Amount = z.Count()
}).ToList();
Reference: How do you perform a left outer join using LINQ extension methods
My problem is hard to solve. i need your help this problem. There is many to many relation in codefirst. But i can not resolve this. i would like to use Predicate func. But i can not resolve it? how to use "Method(Predicate func)"
public int Method<T>(Predicate<T> func)
{
var s1 = this.Uow.X.GetAll().Where(func)
.SelectMany(a => a.OrganizationalUnits.Where(q => Identity.Y.Contains(q.Z)))
.GroupBy(t => t, (k, g) => new
{
Tag = k,
Count = g.Count()
})
.OrderByDescending(g => g.Count);
var s2 = this.Uow.X.GetAll().Where(func)
.SelectMany(a => a.Classes.Where(q => Identity.Y.Contains(q.K)))
.GroupBy(t => t, (k, g) => new
{
Tag = k,
Count = g.Count()
})
.OrderByDescending(g => g.Count);
var s3 = this.Uow.X.GetAll().Where(func)
.SelectMany(a => a.Courses.Where(q => Identity.Y.Contains(q.L)))
.GroupBy(t => t, (k, g) => new
{
Tag = k,
Count = g.Count()
})
.OrderByDescending(g => g.Count);
return s1.ToString().Count() + s2.ToString().Count() + s3.ToString().Count();
}
Here is the way to do it. I also removed the ToString()s on the last line since you don't need an object to be a string to count it.
Call like this: int result = Method<TypeGoesHere>(p => p == aValue);
public int Method<T>(Expression<Func<T, Boolean>> Predicate)
{
var s1 = this.Uow.X.GetAll().Where(Predicate)
.SelectMany(a => a.OrganizationalUnits.Where(q => Identity.Y.Contains(q.Z)))
.GroupBy(t => t, (k, g) => new
{
Tag = k,
Count = g.Count()
})
.OrderByDescending(g => g.Count);
var s2 = this.Uow.X.GetAll().Where(Predicate)
.SelectMany(a => a.Classes.Where(q => Identity.Y.Contains(q.K)))
.GroupBy(t => t, (k, g) => new
{
Tag = k,
Count = g.Count()
})
.OrderByDescending(g => g.Count);
var s3 = this.Uow.X.GetAll().Where(Predicate)
.SelectMany(a => a.Courses.Where(q => Identity.Y.Contains(q.L)))
.GroupBy(t => t, (k, g) => new
{
Tag = k,
Count = g.Count()
})
.OrderByDescending(g => g.Count);
return s1.Count() + s2.Count() + s3.Count();
}
I think you probably want an extension method for whatever type this is. It would look like this (if thisType was type of this). This does not need to be a template since you (but not me) know the type of X.GetAll(). I'm guessing List<int> which would make T int. I've also changed the code to be briefer but have the same functionality. (It might be your original code was doing the wrong thing but this does the same thing.)
Call like this:
thisType something = new something();
someType aValue = X; // don't know the type here.
// do stuff with something
int result = something.Method(p => p == aValue);
Code:
public static int Method(this thisType me, Expression<Func<someType, Boolean>> Predicate)
{
var allOfEm = me.Uow.X.GetAll().Where(Predicate);
var s1 = allOfEm
.SelectMany(a => a.OrganizationalUnits.Where(q => Identity.Y.Contains(q.Z)))
.Distinct();
var s2 = allOfEm
.SelectMany(a => a.Classes.Where(q => Identity.Y.Contains(q.K)))
.Distinct();
var s3 = allOfEm
.SelectMany(a => a.Courses.Where(q => Identity.Y.Contains(q.L)))
.Distinct();
return s1.Count() + s2.Count() + s3.Count();
}
I'm not sure if there is a more efficient way of doing what I'm doing using LINQ... I have two enumerations:
enumA(string): { "Andy", "Bill", "Charlie", "Doug" }
enumB(foo): { "Doug", "Edward", "George", "Bill" } (Note that enumB actually contains objects)
var dictionary = new Dictionary<string,
foreach (var a in enumA)
{
var b = enumB.SingleOrDefault(x => String.Equals(x.ToString(), a));
if (b != null)
dictionary[a] = b;
}
It just seems bad to me to enumerate over enumB over and over again and create a dictionary this way when I'm sure there is probably a more "correct" way to create a dictionary using LINQ.
You can do it efficiently using a
join
and an
ToDictionairy
call afterwards.
var listA = "abcd";
var listB = "cdef";
var tuples = from charFromA in listA
join charFromB in listB
on charFromA.ToString() equals charFromB.ToString() // instead of ToString(), do something complex
select new { A = charFromA, B = charFromB };
var dictionairy = tuples.ToDictionary(keySelector: t => t.A,elementSelector: t => t.B);
var query = from b in enumB.Where(x => x != null)
join a in enumA on b.ToString() equals a
select new { a, b };
var dictionary = query.ToDictionary(x => x.a, x => x.b);
Or with fluent API:
var dictionary = enumB.Where(b => b != null)
.Join(enumA,
b => b.ToString(),
a => a,
(b, a) => new { a, b })
.ToDictionary(x => x.a, x => x.b);
var dictionary = enumA
.Join(enumB, a => a, b => b.ToString(), (a, b) => new { A = a, B = b })
.ToDictionary(i => i.A, i => i.B);
This will throw an exception if there are any duplicate keys, so you can use:
var dictionary = enumA
.Join(enumB, a => a, b => b.ToString(), (a, b) => new { A = a, B = b })
.Aggregate(new Dictionary<string, Foo>(), (dict, i) => {
dict[i.A] = i.B;
return dict;
});
which will keep the last matching value.
var dict = enumA.Join(enumB, a => a, b => b, (a, b) => new {a, b})
.GroupBy(x => x.a)
.ToDictionary(x => x.Key, x => x.First());
GroupBy is to eliminate possible duplicates in enumB.
if enumB duplicates don't exist you can simplify it to
var dict = enumA.Join(enumB, a => a, b => b, (a, b) => new {a, b})
.ToDictionary(x => x.a, x => x.b);
I've been trying to use a lambda for this :
var y = from r in rs.Returns from z in r.Tags where z.Name.Contains(c) select r;
I tried var r = rs.Returns.Where(x=>x.Tags.Where(x=>x.Name.Contains(c)));but it didnt work. What is the correct lambda so I dont have to use y & z
You need a SelectMany to translate the second "from" clause:
var y = rs.Returns
.SelectMany(r => r.Tags, (r, z) => new { r, z })
.Where(pair => pair.z.Name.Contains(c))
.Select(pair => pair.r);
That's a pretty direct translation. Another alternative would be to use:
var y = rs.Returns.Where(r => r.Tags.Any(z => z.Name.Contains(c)));
I'm trying to dynamically create a where clause with link.
Now, creating something like SELECT Product WHERE x = 123 AND y = 349 AND w = 948 is no problem. I'm just adding extra Where filters.
products = products.Where(product => product.Property == 123);
But now i have an unknown number of values that should be tested with an OR operator. The SQL Should be like SELECT Product WHERE x = 123 OR x = 499 OR x = 998 .. and n more OR's
Build a list of numbers to check and do something like the following:
var idsToCheck = new List<int>{123, 789, 654}; //Build from dynamic list
products = products.Where(x => idsToCheck.Contains(x.Id));
The above can be duplicated for v and w if required
var idsToCheck = new List<int>{123, 789, 654}; //Build from dynamic list
products = products.Where(x => idsToCheck.Contains(x.Id));
var propertyToCheck = new List<int>{123, 789, 654};//Build from dynamic list
products = products.Where(x => propertyToCheck.Contains(x.Property));
var numberToCheck = new List<int>{123, 789, 654};
products = products.Where(x => numberToCheck.Contains(x.Number));
If your values to check are already being passed in as enumerables then you don't need to build your xxxToCheck collections. You can simply do the .Contains against the originals
You can use contains on a list or just have the equation like so:
products.Where(product => (product.Property == 123) || (product.Property == 499) || (product.Property == 998));
If you want to compose an OR query from multiple where clauses you really need to compose the predicates in the where clauses instead. Afterall, chaining where clauses would be an AND.
So, if you have the following predicates:
Func<Product, bool> w1 = p => p.x == 123;
Func<Product, bool> w2 = p => p.y == 349;
Func<Product, bool> w3 = p => p.w == 948;
Func<Product, bool> w4 = p => p.Property == 123;
Func<Product, bool> w5 = p => p.x == 499;
Func<Product, bool> w6 = p => p.x == 998;
You can define the following extension method to OR them:
public static Func<T, bool> Or<T>(this Func<T, bool> #this, Func<T, bool> that)
{
return t => #this(t) || that(t);
}
Now you could write:
var products1 = products.Where(w1.Or(w5).Or(w6));
var products2 = products.Where(
((Func<Product, bool>)(p => p.x == 123))
.Or(p => p.y == 349)
.Or(p => p.Property == 123));
If you want to work with lists of clauses then add this extension method:
public static Func<T, bool> Or<T>(this IEnumerable<Func<T, bool>> #this)
{
return #this.Aggregate((Func<T, bool>)(t => true), (a, t) => a.Or(t));
}
Now you can write:
var predicates = new List<Func<Product, bool>>()
{
p => p.x == 123,
p => p.w == 948,
p => p.Property == 123,
p => p.x == 998,
};
var products3 = products.Where(predicates.Or());
If you're writing this against an IQueryable<T> provider then you need to work with Expression<Func<Product, bool>> and not just Func<Product, bool>.
Then you need these extension methods:
public static Expression<Func<T, bool>> Or<T>(
this Expression<Func<T, bool>> #this,
Expression<Func<T, bool>> that)
{
var param =
Expression
.Parameter(typeof(T), "t");
var body =
Expression
.Or(
Expression
.Invoke(#this, param),
Expression
.Invoke(that, param));
return
Expression
.Lambda<Func<T, bool>>(body, param);
}
public static Expression<Func<T, bool>> Or<T>(
this IEnumerable<Expression<Func<T, bool>>> #this)
{
return #this.Aggregate((Expression<Func<T, bool>>)(t => true), (a, t) => a.Or(t));
}
The calling code still works the same:
var predicatesX = new List<Expression<Func<Product, bool>>>()
{
p => p.x == 123,
p => p.w == 948,
p => p.Property == 123,
p => p.x == 998,
};
var products3X = products.Where(predicatesX.Or());
Is this what you were looking for?