Are the following two queries equivalent? If they are not equivalent, which performs better? Is there a way I can see the sql output of the queries?
var query1 = items.Where(i => i.Enabled == true).Where(i => i.Name == "Bob");
var query2 = items.Where(i => i.Enabled == true && i.Name == "Bob");
As Andrew says, the two options are equivalent. One practically useful difference is that you can easily generate conditions in the Where clause programmatically. For example if you wanted to exclude certain names:
var query = items;
for(string name in excluded)
query = query.Where(i => i.Name != excluded);
This is something that cannot be done easily when writing query using && operator.
Both queries will translate to the same SQL - you can use a tool like LinqPad to verify this if you want (I just did). The LINQ provider that translate your expression trees into T-SQL is smart enough to understand that these queries are synonymous. Of course this means that both queries will perform equally as well.
Related
I have a rather complex condition for my WHERE query in the database. If I were to use straight SQL I probably would put that part of the SQL query into a named variable to signify its semantic purpose.
If I were to use straight Linq I would use a function-call that matches the Where() predicate where the function name would tell me the purpose of the filter.
Unfortunately one can't seem to use sub-functions in Linq to SQL because then the query cannot be resolvd to SQL.
Is there a way to achieve this?
Here is the original Linq-to-SQL query:
query = query.Where(
f => f.Table1.Any(
t1 =>
(t1.Table2.Any(t2 => t2.Header == Decoder.Identifier
&& DbFunctions.Like(t2.Content, pattern)))
||
(!t1.Table2.Any(t2 => t2.Header == Decoder.Identifier)
&& DbFunctions.Like(t1.Text, pattern))
));
What I would like is something like this:
query = query.Where(
f => f.Table1.Any(
t1 =>
HasCondition1(t1, pattern)
||
HasCondition2(t1, pattern)
));
we are Entity Framework in our project. Need to know the performance impact between .ANY() and Expressions to form Where clause.
In the below function i used two approach to get result:
APPROACH 1 - Form Lambda expression query using ANY()
From my observation using .Any() is not adding where clause when query is executed(checked in sql profiler) what EF does is gets all matched inner joined records store in-memory and then apply condition specified in .ANY()
APPROACH 2 - Form Expression Query Starts
With Expressions i'm explicitly forming where clause and executing.checked the same in SQL query Profiler i'm able to see where clause.
Note: To form expression where clause i'm doing additional loops and "CombinePredicates".
Now, my doubts are:
which approach will improve performance. Do i need to go with Lambda
with .ANY() or Expressions?
what is the right way to from where clause to improve performance?
If not the two approach suggest me the right way to do it
private bool GetClientNotifications(int clientId, IList<ClientNotification> clientNotifications)
{
IList<string> clientNotificationList = null;
var clientNotificationsExists = clientNotifications?.Select(x => new { x.Name, x.notificationId
}).ToList();
if (clientNotificationsExists?.Count > 0)
{
//**Approach 1 => Form Lamada Query starts**
notificationList = this._clientNotificationRepository?.FindBy(x => clientNotificationsExists.Any(x1 => x.notificationId == x1.notificationId && x.clientId ==
clientId)).Select(x => x.Name).ToList();
**//Form Lamada Query Ends**
//**Approach 2 =>Form Expression Query Starts**
var filterExpressions = new List<Expression<Func<DbModel.ClientNotification, bool>>>();
Expression<Func<DbModel.ClientNotification, bool>> predicate = null;
foreach (var clientNotification in clientNotificationsExists)
{
predicate = a => a.clientId == clientId && a.notificationId == clientNotification .notificationId;
filterExpressions.Add(predicate);
}
predicate = filterExpressions.CombinePredicates<DbModel.ClientNotification>(Expression.OrElse);
clientNotificationList = this._clientNotificationRepository?.FindBy(predicate).Select(x => x.Name).ToList();
//**Form Expression Query Ends**
}
return clientNotificationList;
}
If non of the approaches were good please suggest me the right way to do.
I noticed the clientId being used on both approaches is used on conditions linked to clientNotificationsExists but there is no actual relationship with its objects so this condition can be moved up one level. This might bring a minuscule benefit as the overall sql will be smaller without the duplicate clauses.
From the described behavior the first approach filter is not being translated to sql so it is being resolved at the client side however, if it could be translated the performance would be similar or identical.
If you want to generate an IN sql clause you can use an array and use the Contains method within your filter expression. That could perhaps improve a little bit but don't get your hopes too high.
Try the following:
private bool GetClientNotifications(int clientId, IList<ClientNotification> clientNotifications)
{
IList<string> clientNotificationList = null;
var clientNotificationsExists = clientNotifications?
.Select(x => new { x.Name, x.notificationId }).ToList();
if (clientNotificationsExists?.Count > 0)
{
var notificationIds = clientNotificationsExists.Select(x => x.notificationId).ToArray();
clientNotificationList = this._clientNotificationRepository?
.FindBy(x => x.clientId == clientId && notificationIds.Contains(x.notificationId));
}
return clientNotificationList;
}
I am relatively new to Entity Framework 6.0 and I have come across a situation where I want to execute a query in my C# app that would be similar to this SQL Query:
select * from periods where id in (select distinct periodid from ratedetails where rateid = 3)
Is it actually possible to execute a query like this in EF or would I need to break it into smaller steps?
Assuming that you have in your Context class:
DbSet<Period> Periods...
DbSet<RateDetail> RateDetails...
You could use some Linq like this:
var distincts = dbContext.RateDetails
.Where(i => i.rateId == 3)
.Select(i => i.PeriodId)
.Distinct();
var result = dbContext.Periods
.Where(i => i.Id)
.Any(j => distincts.Contains(j.Id));
Edit: Depending on your entities, you will probably need a custom Comparer for Distinct(). You can find a tutorial here, and also here
or use some more Linq magic to split the results.
Yes, this can be done but you should really provide a better example for your query. You are already providing a bad starting point there. Lets use this one:
SELECT value1, value2, commonValue
FROM table1
WHERE EXISTS (
SELECT 1
FROM table2
WHERE table1.commonValue = table2.commonValue
// include some more filters here on table2
)
First, its almost always better to use EXISTS instead of IN.
Now to turn this into a Lambda would be something like this, again you provided no objects or object graph so I will just make something up.
DbContext myContext = this.getContext();
var myResults = myContext.DbSet<Type1>().Where(x => myContext.DbSet<Type2>().Any(y => y.commonValue == x.commonValue)).Select(x => x);
EDIT - updated after you provided the new sql statement
Using your example objects this would produce the best result. Again, this is more efficient than a Contains which translates to an IN clause.
Sql you really want:
SELECT *
FROM periods
WHERE EXISTS (SELECT 1 FROM ratedetails WHERE rateid = 3 AND periods.id = ratedetails.periodid)
The Lamda statement you are after
DbContext myContext = this.getContext();
var myResults = myContext.DbSet<Periods>()
.Where(x => myContext.DbSet<RateDetails>().Any(y => y.periodid == x.id && y.rateid == 3))
.Select(x => x);
Here is a good starting point for learning about lamda's and how to use them.
Lambda Expressions (C# Programming Guide).
this is your second where clause in your query
var priodidList=ratedetails.where(x=>x.rateid ==3).DistinctBy(x=>x.rateid);
now for first part of query
var selected = periods.Where(p => p.id
.Any(a => priodidList.Contains(a.periodid ))
.ToList();
Given tables as:
Table1
id
stringfield1
stringfield2
stringfield3
stringfield4
Table2
id
table1_id
stringfield1
datefield1
Given a UI allow user to make fency query on:
dropdwonlist1 with any and table1.stringfield1 values
dropdwonlist2 with any and table1.stringfield2 values
dropdwonlist3 with any and table1.stringfield3 values
dropdwonlist4 with any and table1.stringfield4 values
dropdwonlist5 with any and table2.stringfield1 values
dropdwonlist6 with [any, the, before, after, between]
calendar1 to link with table2.datefield1
calendar2 to link with table2.datefield1
And as result datagridview with everyfields.
I want to build conditional query as if not "any" add this condition.
Considering that, simple LINQ query is not applicable:
Table2
.Where(x => x.stringfield1 == dropdwonlist1.SelectedValue)
.Where(x => x.stringfield2 == dropdwonlist2.SelectedValue)
.Where(x => x.stringfield3 == dropdwonlist3.SelectedValue)
(...)
There is Expression trees in documentation but that looks too much.
Is there simplest way to build my dynamic query ?
Expression trees look scarier than they are, but you are right, in your situation they are unnecessary: you could use a static condition that is smart enough to ignore dropdowns that have no selection. You can do it like this:
Table2
.Where(x => dropdwonlist1.SelectedValue == null || x.stringfield1 == dropdwonlist1.SelectedValue)
.Where(x => dropdwonlist2.SelectedValue == null || x.stringfield2 == dropdwonlist2.SelectedValue)
.Where(x => dropdwonlist3.SelectedValue == null || x.stringfield3 == dropdwonlist3.SelectedValue)
I've used LINQKit for similar scenarios with great success.
Specifically, you should be able to use the PredicateBuilder to accomplish what you're looking for.
It's common to forget that you can keep building up LINQ expressions across multiple statements. It's one of the great niceties of LINQ. I would simplify dasblinkenlight's answer for the LINQ-to-SQL translation that's going to happen afterward to:
IQueryable<T> query = Table2;
if (dropdownlist1.SelectedValue == null)
query = query.Where(x => x.stringfield1 == dropdownlist1.SelectedValue);
// etc
That way anything with a null value doesn't get mixed up into the where clauses at all, reducing the chances the generated SQL has unnecessary conditions in it.
I like Donut's answer best as a more generalized solution though - for example LINQKit would let you write a loop over the 6 dropdowns that writes each where clause if necessary.
Here's my error
Unable to create a constant value of type 'Courses.Model.Track'. Only primitive types or enumeration types are supported in this context.
and here's the code that causes it:
model.Courses = db.Courses
.Where(c => model.Tracks.Any(t => t.Certification.ID == certificate))
.ToList();
Also, model.Courses is IEnumerable<Courses>, and I'm not sure if that has anything to do with my problem.
Could anybody shed some light on this for me? Many thanks.
db.Courses is an IQueryable. While the syntax is virtually identical to the LINQ methods of IEnumerable, under the hood they're completely different.
The IQueryable code isn't actually exectued anywhere at all. It just creates a bunch of Expression objects that different query providers are able to use to do...whatever they want (in this case query a database). Those query providers need to specifically have code to handle any given type of input. There are some things that they either can't sensibly transform into a SQL query, or things that the programmers simply didn't think of or choose to handle (even if it might have a sensible SQL translation).
In sort, the query provider just doesn't know how to translate model.Tracks.Any(t => t.Certification.ID == certificate) into SQL.
You simply need to know what types of code is and isn't supported by the query provider that you're using and try to manipulate the code you have into something that it can handle. Something like this should work:
var certificates = model.Tracks.Select(t => t.Certification.ID).ToList();
model.Courses = db.Courses
.Where(c => certificates.Contains(c))
.ToList();
If this were C# code executing all of this in LINQ to objects the two queries would be identical, but to a query provider they're not. They simply have special support for knowing when they see List.Contains to map it to a SQL IN clause. They didn't add specific support for what you did in your first query.
Try using LINQ 'Where In', this should solve your problem:
var names = new string[] { "Alex", "Colin", "Danny", "Diego" };
var matches = from person in people
where names.Contains(person.Firstname)
select person;
OR
var matches = from person in people
where person.Firstname == "Alex" ||
person.Firstname == "Colin" ||
person.Firstname == "Danny" ||
person.Firstname == "Diego"
select person;
http://blogs.msdn.com/b/alexj/archive/2009/03/26/tip-8-writing-where-in-style-queries-using-linq-to-entities.aspx
My apologies for the almost unnecessary question, although #klugerama did help me figure it out.
There was a problem with this:
model.Courses = db.Courses
.Where(c => model.Tracks.Any(t => t.Certification.ID == certificate))
.ToList();
Until I changed it to this:
model.Courses = db.Courses
.Where(c => c.Track.Certification.ID == certificate)
.ToList();
Again, my apologies. Thanks to everyone for their input.