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.
Related
Trying to add a second where clause to a linq expression but it won't register.
var query = _dbSetBookedResource.AsQueryable<Resource>();
var resources = (from Resource in query where Resource.DateFrom == date select Resource)
if(true)
{
resources.Where(b => b.MemberId == currentUserId);
}
For some reason the second where clause won't register.
For some reason the second where clause won't register.
That's because you're not using the return value anywhere. That's just setting up a query, but then ignoring it. No LINQ methods change the value they're called on - instead they create a new query which has the appropriate filtering, projection etc.
You need:
resources = resources.Where(b => b.MemberId == currentUserId);
Also note that your initial query could be written more simply as:
var resources = query.Where(r => r.DateFrom == date);
Query expressions are overkill when all you want is a simple filter or projection.
I have a PredicateBuilder which I got it from
http://www.albahari.com/nutshell/predicatebuilder.aspx
And here is how I use it:
var Expression = PredicateBuilder.True<UCM_UserAgent>();
Expression = Expression.And(item => item.AgentText == "TestUserAgent Value");
Func<UCM_UserAgent, bool> SearchCriteria = Expression.Compile();
var Data = Context.UCM_UserAgent
.Where(SearchCriteria)
.ToList();
And when I checked SQL Profiler on my database:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[AgentText] AS [AgentText],
FROM [dbo].[UCM_UserAgent] AS [Extent1]
Now, where is the condition I added? I could not solve this. Unfortunately, this Entity Framework and Predicate Builder - Predicates being Ignored in SQL Query did not help either.
Edit:
To eliminate any misunderstandings; I do not want to use as x => x.AgentText = "SomeText". Because I want to build a dynamic LINQ query, thus I use PredicateBuilder.
If you want the predicate to be hadled by LINQ to Entities you need to pass the Expression<Func<T,bool>> version to the Queryable.Where() method instead of passing the Func<T,bool> version to the Enumerable.Where() method as you are currently doing, i.e. do not compile the expression into IL before calling the Where method or you will necessarily get the LINQ to Objects version.
I want to retrieve commissions with a certain order number.
This works:
var expression = from commission in db.Auftraege
where commission.Auftragsnummer == orderNbr
select new Commission() { EF_Commission = (commission as Auftrag) };
return expression.ToList();
However, if i transform this to use a dynamic where clause (because i want to apply some more filters), the where-clause does not seem to be applied. Instead, all commissions are returned instead of only those with a specific number:
//base query
var expression = from commission in db.Auftraege select new Commission() { EF_Commission = (commission as Auftrag) };
//now add a where clause if the input parameter was specified
if (orderNbr >= 0)
expression.Where(commission => commission.EF_Commission.Auftragsnummer == orderNbr);
return expression.ToList();
I have looked at a dozen examples but they all seem to do it this way. Does anybody have an idea why the second query ignores the where clause?
You need to assign the interim expression to something (perhaps to itself). expression.Where() does not alter the existing query - it returns a new one.
So:
expression = expression.Where(...);
I have a query, which throws an exception in Linq to Sql.
Local sequence cannot be used in LINQ to SQL implementation of query operators except the Contains() operator.
I have seen plenty of related questions so I (roughly) understand the reason WHY it doesn't work (the value term in the lambda expression cannot be converted into a string value for the SQL query), but I cannot see HOW to should restructure this.
var searchTerms = userQuery.Split(' ').ToList().ConvertAll(term => term.ToLower());
var qry = (from tree in someQueryable
join widget in myDb.Widgets
on tree.ParentId equals widget.Id
where
searchTerms.All(term => tree.Title.ToLower().Contains(term) //Can't use Contains on term, as term isn't a local variable
|| searchTerms.All(term => widget.Title.ToLower().Contains(term) //And again here
|| (tree.Description != null && searchTerms.All(term =>
tree.Description.ToLower().Contains(term))) //And here
orderby tree.SomeDate descending
select tree);
How can I get all trees whose Title, Description or ParentWidget.Title contain ALL of the search terms?
I have tried iterating over each term, however this gives me the issue of matching a single term, not all terms.
Update
I resolved the issue... by changing my requirements :)
I am still very interested to know how my initial requirements could be achieved.
from term in SearchTerms
from tree in someQueryable
join widget in myDb.Widgets
where tree.Title.ToLower().Contains(term) ||
widget.Title.TowLower().Contains(term) ||
(tree.Description != null && tree.Description.ToLower.Contains(term))
orderby tree.SomeDate descending
select tree
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.