Linq convert a Method Syntax to Query Expression - linq

Recently I wrote this query with Linq (Method Syntax), notes:
g.CmsContents is a Navigatiola Property.
I would like to know how to rewrite this code as a Linq Query Expression if it is possible.
var myGroupsTypesList = from g in context.CmsGroupsTypes
where g.CmsContents.Any(x => x.ContentId == myContentId)
select g;
Any idea? Thanks for your support :-)

That's already a query expression. If you mean you want to convert the Any part to another query expression - you can't. There's no query expression support for Any.
If you actually meant it the other way round, your query is equivalent to:
var myGroupsTypesList = context.CmsGroupsTypes
.Where(g => g.CmsContents.Any(x => x.ContentId == myContentId));

Related

Why is the "Select" of a Method Syntax is in another parenthesis?

var sample = db.Database.OrderByDescending(x => x.RecordId).Select(y => y.RecordId).FirstOrDefault();
I don't know if my title is correct / right. Just want to ask why this query the select is in another ( )?. As for the example .Select(y => y.RecordId) unlike the query I use to be
var sample = (from s in db.Databse where s.RecordId == id select s) I know this is the same right?. Then what is the why it is in another parenthesis?. Anyone has an idea or can anyone explain it why?. Thanks a lot.
In your first example, you're using "regular" C# syntax to call a bunch of extension methods:
var sample = db.Database
.OrderByDescending(x => x.RecordId)
.Select(y => y.RecordId)
.FirstOrDefault();
(They happen to be extension methods here, but of course they don't have to be...)
You use lambda expressions to express how you want the ordering and projection to be performed, and the compiler converts those into expression trees (assuming this is EF or similar; it would be delegates for LINQ to Objects).
The second example is a query expression, although it doesn't actually match your first example. A query expression corresponding to your original query would be:
var sample = (from x in db.Database
orderby x.RecordId descending
select x.RecordId)
.FirstOrDefault();
Query expressions are very much syntactic sugar. The compiler effectively converts them into the first form, then compiles that. The range variable declared in the from clause (x in this case) is used as the parameter name for the lambda expression, so select x.RecordId becomes .Select(x => x.RecordId).
Things become a bit more complicated with joins and multiple from clauses, as then the compiler introduces transparent identifiers to allow you to work with all the range variables that are in scope, even though you've really only got a single parameter. For example, if you had:
var query = from person in people
from job in person.Jobs
order by person.Name
select new { Person = person, Job = job };
that would be translated into the equivalent of
var query = people.SelectMany(person => person.Jobs, (person, job) => new { person, job } )
.OrderBy(t => t.person.Name)
.Select(t => new { Person = t.person, Job = t.job });
Note how the compiler introduces an anonymous type to combine the person and job range variables into a single object, which is used later on.
Basically, query expression syntax makes LINQ easier to work with - but it's just a translation into other C# code, and is neatly wrapped up in a single section of the C# specification. (Section 7.16.2 of the C# 5 spec.)
See my Edulinq blog post on query expressions for more detail on the precise translation from query expressions to "regular" C#.

LinqKit PredicateBuilder adding to linq query

I have a linq query which I want to add some additional, optional WHERE conditions to using LinqKit Predicate Builder. However, I an struggling to get the additional predicate to work
This is my initial query:
var query = (from OP in ctx.OrganisationProducts
where OP.OrganisationID == orgID
orderby OP.Product.Name, OP.Product.VersionName
select OP).Include("Product");
As you can see, there is JOIN in there.
I then wish to add additional predicates if required:
if(!includeDisabledP42Admin || !includeDisabledOrgAdmin)
{
var pred = PredicateBuilder.True<OrganisationProduct>();
if (!includeDisabledP42Admin)
pred.And(op => op.Enabled);
if (!includeDisabledOrgAdmin)
pred.And(op => op.AccessLevel == "NA" || op.AccessLevel == "NU");
query = query.Where(pred);
}
However, the generated SQL is unchanged and the query returns the same number of rows.
I thought I might have had to do the Expand conversion as so:
query = query.AsExpandable().Where(pred);
But this causes a runtime error.
I think the issue is the fact that I am adding the predicate to a query that is already no longer a pure OrganisationProduct object, however I would like advise on how I insert my predicate at the right place.
Thanks and all :-)
You have to assign the return value of And to the predicate:
pred = pred.And(op => op.Enabled);
Side note: you may like this predicate builder that works without Expand/AsExpandable, but has the same syntax.

Nhibernate linq. The where extension method does not add the where clause to the SQL command, why?

I want to add the where clause to a linq statement, but it doesn't behave as i would expected it to.
When i use this code:
IQueryable<Employee> EmpQuery = from e in Session.Query<Employee>() where e.Surname == "Test" select e;
EmpQuery.ToList();
or i use this code:
IQueryable<Employee> EmpQuery = (from e in Session.Query<Employee>() select e).Where(e => e.Surname == "Test");
EmpQuery.ToList();
The where clause is included in the SQL command, but when i try it this way:
IQueryable<Employee> EmpQuery = from e in Session.Query<Employee>() select e;
EmpQuery.Where(e => e.Surname == "Test");
The where clause is not included in the SQL command. Why is this? Is there another way to dynamically add criteria to a Nhibernate Linq query?
You're not using the return value of Where. LINQ is designed around functional concepts - calling Where doesn't modify the existing query, it returns a new query which applies the filter. The existing query remains as it was - which means you can reuse it for (say) a different filter.
Note that your current query expression (from x in y select x, effectively) is pretty pointless. I would suggest simply writing:
var query = Session.Query<Employee>().Where(e => e.Surname == "Test");
Just to clarify on Jon's remark, your implementation would be fine with the following tweak:
IQueryable<Employee> modifiedQuery = EmpQuery.Where(e => e.Surname == "Test");
Then just invoke the appropriate enumerator (ToList, ToArray, foreach) on modifiedQuery. And I wouldn't say that it create a complete new query, but instead creates a query which wraps around the original (kind of along the lines of the adapter pattern). Granted, your example doesn't need the additions, but this is how you would add additional criteria onto an existing LINQ expression, and that is what your question actually asked.

Lost with LINQ and Expressions

I'm trying to write a LINQ query on some objects where I need to only do a select if a filter value is set.
Is there a way to "change" the query dynamically to only do a select if this is set.
Use where to find the items of interest, e.g.:
collection.Where(i => PassesFilter(i)).Select(i => i.InterestingValue);
var query = Somthing().Where(x => x.IsSomethingYouAlwaysFilterBy);
if(FilterValueIsSet(filterValue))
{
query = query.Where(x => x.Property == filterValue)
}
I'm not sure I understand your question, but you can use predicate builder. Predicate Builder example here

Linq expression subsonic 3.0.0.3

I want to 'build' a combined query for Subsonic 3.0.0.3, what is the best way for this?
I tried;
Expression<Func<Person, bool>> exp = p => true;
Expression<Func<Person, bool>> fContinent = p => p.ContinentID == 1;
Expression<Func<Person, bool>> fType = p => p.TypeID == 1;
exp = Expression.Lambda<Func<Person, bool>>(Expression.AndAlso(exp, fContinent), exp.Parameters);
exp = Expression.Lambda<Func<Person, bool>>(Expression.AndAlso(exp, fType), exp.Parameters);
var personList = Person.Find(exp);
But that will give the exception "The binary operator AndAlso is not defined ..."
I also tried using predicates but that will throw exceptions as well (Expression.Invoke is not supported).
In subsonic 2 I would have used the SqlQuery object, but I would like to know the proper way to do this in version 3 using linq / expressions.
Have you tried And instead of AndAlso?
The right way to do this is to combine the lambda expression bodies, like this:
exp = Expression.Lambda<Func<Person, bool>>(
Expression.And(exp.Body, fContinent.Body), exp.Parameters);
Even if And is supported by your query provider, you'll also need to replace the parameter references in fContinent's Body with references to the parameter defined in exp--as is, your two expression bodies (combined with And) reference two distinct parameters, each named p.
See my answer to this question for the cleanest method to replace expression parameters.
I asked this question, but I am using the combined query in subsonic just like you.
In short, you want to use a PredicateBuilder to build up the query. When you want to execute it in your subsonic object (assuming ActiveRecord), use code like this:
var predicate = /* Build up predicate with PredicateBuilder */;
var recs = SubsonicClass.All().Where(predicate.Compile()).ToList();

Resources