LINQ: adding where clause only when a value is not null - c#

I know a typical way is like this:
IQueryable query = from staff in dataContext.Staffs;
if(name1 != null)
{
query = from staff in query where (staff.name == name1);
}
However, from a program we took over from other developers, we saw code like this:
IQueryable query = from staff in dataContext.Staffs;
query = from staff in query where (name1 == null || staff.name == name1);
If this is a normal SQL statement, I would definitely say that the 2nd one is a bad practice. Because it adds a meaningless where clause to the query when name1 is null.
But I am new to LINQ, so I am not sure if LINQ is different?

you can write it like
IQueryable query = from staff in dataContext.Staffs;
query = from staff in query where (name1 != null && staff.name == name1);
This way second part of your condition will not be evaluated if your first condition evaluates to false
Update:
if you write
IQueryable query = from staff in dataContext.Staffs;
query = from staff in query where (name1 == null || staff.name == name1);
and name1 is null second part of your condition will not be evaluated since or condition only requires one condition to return true
plz see this link for further detail

Often this sort of thing feels smoother to write using the fluent syntax, rather than the query syntax.
e.g.
IQueryable query = dataContext.Staffs;
if(name1 != null)
{
query = query.Where(x => x.name == name1);
}
So if name1 is null, you just don't do any Where() call. If you have multiple different filters, all of which may or may not be required, and perhaps various different sort orders, I find this becomes a lot more manageable.
Edit for alex: OK, I was answering the question about adding a where clause only when a value is not null. In response to the other part of the question, I tried this out with Entity Framework 4 to see what SQL that LINQ produced. You do this by casting query to an ObjectQuery and calling .ToTraceString(). The results were that the WHERE clause came out as follows:
WHERE #p__linq__0 IS NULL OR [Extent1].[name] = #p__linq__1
So, yes, it's classic bad SQL, if you have an index on the name column, don't expect it to be used.
Edit #2: Tried this again using LINQ to SQL rather than Entity Framework, with rather different results. This time, trying the query with name1 being null results in no WHERE clause at all, as you'd hope; trying it with name1 being "a" resulted in a simple WHERE [t0].[name] = #p0 and #p0 sent as "a". Entity Framework does not seem to optimize thus. That's a bit worrying.

The best way to do this is to create yourself an extension method that will take in a conditional statement and a where expression. If the condition is true then it will use the where expression else it will not use it. This can dramatically clean up your code, eliminating the need for if statements.
public static class LinqExtensions
{
public static IQueryable<T> WhereIf<T>(this IQueryable<T> query, bool condition, Expression<Func<T, bool>> whereClause)
{
if (condition)
{
return query.Where(whereClause);
}
return query;
}
}
Now you can write your code like this:
IQueryable<Staffs> query = dataContext.Staffs.AsQueryable().WhereIf(name1 != null, x => x.Name == name1);

So I tried the .Where(..., x => ...) extension method listed here as an answer but it doesn't work against Entity Framework as Linq To Entities doesn't know how to translate that into TSQL.
So here's my solution getting my Func on:
Expression<Func<SomeEfPoco, bool>> columnBeingFilteredPredicate = x => true; // Default expression to just say yes
if (!string.IsNullOrWhiteSpace(someColumnBeingFilteredValue))
{
columnBeingFilteredPredicate = x => x.someColumnBeingFiltered == someColumnBeingFilteredValue;
}
_context.SomeEfPocos.Where(x => ..... &&
..... &&
..... &&)
.Where(columnBeingFilteredPredicate);
someColumnBeingFilteredValue in my case is a string parameter on the encapsulating method with a default value of NULL.

LINQ is diffrent in some other causes (not in this causes),
LINQ is the way to get data in the "Faster way" with a littel code and clear cod as possible, there a many benefits of LINQ:
Makes it easier to transform data into objects. I'm sure you've heard the term "Impedence Mismatch" being used quite often, meaning that LINQ reduces the amount of work you must do to translate between object-oriented code and data paradigms such as hierarchical, flat-file, messages, relational, and more. It doesn't eliminate the "Impedence Mismatch" because you must still reason about your data in its native form, but the bridge from here to there is (IMO) much shorter.
A common syntax for all data. Once you learn query syntax, you can use it with any LINQ provider. I think this is a much better development paradigm than the Tower of Babel that has grown over the years with data access technologies. Of course, each LINQ provider has unique nuances that are necessary, but the basic approach and query syntax is the same.
Strongly typed code. The C# (or VB.NET) query syntax is part of the language and you code with C# types, which are translated into something a provider understands. This means that you gain the productivity of having your compiler find errors earlier in the development lifecycle than elsewhere. Granted, many errors in stored proc syntax will generate errors when you save, but LINQ is more general than SQL Server. You have to think of all the other types of data sources that generate runtime errors because their queries are formed with strings or some other loosely typed mechanism.
Provider integration. Pulling together data sources is very easy. For example, you can use LINQ to Objects, LINQ to SQL, and LINQ to XML together for some very sophisticated scenarios. I think it's very elegant.
Reduction in work. Before LINQ, I spent a lot of time building DALs, but now my DataContext is the DAL. I've used OPFs too, but now I have LINQ that ships with multiple providers in the box and many other 3rd party providers, giving me the benefits from my previous points. I can set up a LINQ to SQL DataContext in a minute (as fast as my computer and IDE can keep up).
Performance in the general case doesn't become an issue. SQL Server optimizes queries quite well these days, just like stored procs. Of course, there are still cases where stored procs are necessary for performance reasons. For example, I've found it smarter to use a stored proc when I had multiple interactions between tables with additional logic inside of a transaction. The communications overhead of trying to do the same task in code, in addition to getting the DTC involved in a distributed transaction made the choice for a stored proc more compelling. However, for a query that executes in a single statement, LINQ is my preferred choice because even if there was a small performance gain from a stored proc, the benefits in previous points (IMO) carry more weight.
Built-in security. One reason I preferred stored procs before LINQ was that they forced the use of parameters, helping to reduce SQL injection attacks. LINQ to SQL already parameterizes input, which is just as secure.
LINQ is declarative. A lot of attention is paid to working with LINQ to XML or LINQ to SQL, but LINQ to Objects is incredibly powerful. A typical example of LINQ to Objects is reading items from a string[]. However, that's just a small example. If you think about all of the IEnumerable collections (you can also query IEnumerable) that you work with every day, the opportunities are plentiful. i.e. Searching an ASP.NET ListBox control for selected items, performing set operations (such as Union) on two collections, or iterating through a List and running a lambda in a ForEach of each item. Once you begin to think in LINQ, which is declarative in nature, you can find many of your tasks to be simpler and more intuitive than the imperative techniques you use today.
I could probably go on, but I'd better stop there. Hopefully, this will provide a more positive view of how you could be more productive with LINQ and perhaps see it as a useful technology from a broader perspective.

I've seen this pattern in standard SQL, and it seems useful if you have several parameters that may be NULL. For example:
SELECT * FROM People WHERE ( #FirstName IS NULL OR FirstName = #FirstName )
AND ( #LastName IS NULL OR LastName = #LastName )
If you see this in LINQ, it's possible they just blindly translated their old SQL-queries.

I like use the Expression
e.g.
Expression<Func<Persons, bool>> expresionFinal = c => c.Active == true;
if (DateBirth.HasValue)
{
Expression<Func<Persons, bool>> expresionDate = c => (EntityFunctions.TruncateTime(c.DateBirth) == DateBirth);
expresionFinal = PredicateBuilder.And(expresionFinal, expresionDate);
}
IQueryable query = dataContext.Persons;
query = query.Where(expresionFinal);

For EF Core I broke it up like this:
IQueryable<Partners> recs = contextApi.Partners;
if (status != -1)
{
recs = recs.Where(i => i.Status == status);
}
recs = recs.OrderBy(i => i.Status).ThenBy(i => i.CompanyName);
foreach (var rec in recs)
{
}
I had to be explicit with my typing instead of relying on var.

I like the idea with Extension
public static IQueryable<T> WhereIf<T>(this IQueryable<T> query, bool condition, Expression<Func<T, bool>> whereClause)
=> condition ? query.Where(whereClause) : query;

No, I am not strongly agree with you.
here you just gave a simple logic
if(name1 != null)
// do your stuff
but what will happen if you do something different with the name1 that have null value..!!
Ok, now consider this situation.
In this example you shows how to handle possible null values in source collections.
An object collection such as an IEnumerable<T> can contain elements whose value is null.
If a source collection is null or contains an element whose value is null,
and your query does not handle null values, a NullReferenceException will be thrown when you execute the query.
Probably this could be a issue...

I use the extension method below. It's less flexible than the WhereIf extension from the other answers, but it's shorter to use.
public static IQueryable<T1> FilterBy<T1, T2>(this IQueryable<T1> query, T2 expectedValue, Expression<Func<T1, T2>> propertyAccessor)
{
if (propertyAccessor == null) throw new ArgumentNullException(nameof(propertyAccessor));
if (expectedValue == null) return query;
var equalExpr = Expression.Equal(propertyAccessor.Body, Expression.Constant(expectedValue, typeof(T2)));
var lambda = Expression.Lambda<Func<T1, bool>>(equalExpr, propertyAccessor.Parameters);
return query.Where(lambda);
}
It can be used like:
var query = dataContext.Staffs.FilterBy(name, s => s.Name);

Related

Case-insensitive "contains" in Linq

I have a mvc project which I use linq in it.
In my database there is some records, for example "Someth ing","SOmeTH ing","someTh ing","SOMETH ING","someTH ING"
I want to do this:
SELECT * FROM dbo.doc_dt_records WHERE name LIKE '%' + #records.Name + '%'
However if I run this code, list.Count returns 0. What should I do?
records.Name = "someth ing"; //for example
var rec = db.Records.ToList();
var lists = rec.Where(p => p.Name.Contains(records.Name)).ToList();
if (lists.Count > 0)
{
// do sthng
}
Thanks for your helps...
the easy way is to use ToLower() method
var lists = rec.Where(p => p.Name.ToLower().Contains(records.Name.ToLower())).ToList();
a better solution (based on this post: Case insensitive 'Contains(string)')
var lists = rec.Where(p =>
CultureInfo.CurrentCulture.CompareInfo.IndexOf
(p.Name, records.Name, CompareOptions.IgnoreCase) >= 0).ToList();
That is totally not a LINQ issue.
Case sensitiivty on the generated SQL depends on the collation relevant for the table. Which in your case likely is case insensitive.
You would get the same result from any SQL you emit.
use IndexOf and StringComparison.OrdinalIgnoreCase:
p.Name.IndexOf(records.Name, StringComparison.OrdinalIgnoreCase) >= 0;
You can create an extension function like this:
public static bool Contains(this string src, string toCheck, StringComparison comp)
{
return src.IndexOf(toCheck, comp) >= 0;
}
To my understanding, this question does not have an unambiguous answer. The matter is that the best way of doing this depends on details which aren't provided in the question. For instance, what exact ORM do you use and what precise DB server you are connected to. For example, if you use Entity Framework against MS SQL Server, you better do not touch your LINQ expression at all. All you need to do is to set the case-insensitive collation on the database/table/column you compare your string with. That will do the trick much better than any change of your LINQ expression. The matter is that when LINQ is translated to SQL, it better be the straight comparison of the column having case-insensitive collation to your string than anything else. Just because it usually works quicker and it is the natural way to do the trick.
You do not want the final query to be something like:
SELECT *
FROM AspNetUsers U
WHERE UPPER(U.Name) LIKE '%SOMETHING%';
It is much better to come up with something like:
SELECT *
FROM AspNetUsers U
WHERE U.Name LIKE '%SOMETHING%';
But with a case-insensitive collation of [Name] column. The difference is that if you have let's say index containing [Name] column, the second query might use it, the first one would do the full scan of the table anyway.
So if let's say records references to DBSet<T> and the record is just one object of type T. You code would be like this:
var lists = records.Where(p => p.Name.Contains(record.Name)).ToList();
And you do the rest on SQL-server. Or if all you need to know is there any value in the list and do not need these values, it would be even better to do like this:
if (records.Any(p => p.Name.Contains(record.Name)))
{
// do something
}
Generally speaking, if you use any sort of ORM connected to any sort of SQL server, you better do case-insensitivity by setting up appropriate parameters of your server/database/table/column. And only if it is impossible or by far too expensive, you consider other possibilities. Otherwise, you might bang into some unexpected and very unpleasant behaviour. For instance, Entity Framework Core 2.x if it cannot translate your LINQ expression straightway into SQL query, is doing different tricks replacing server-side operations with client-side ones. So you can end up with a solution which fetches all data from the table to the client and filter it there. It might be quite a problem if your table is big enough.
As for the situation when LINQ query is processed locally, there are a lot of ways to do the trick. My favourite one is the next:
var lists = records.Where(p => p.Name
.Contains(record.Name, StringComparison.InvariantCultureIgnoreCase))
.ToList();
try this
var lists = rec.Where(p => String.Equals(p.Name,records.Name,StringComparison.OrdinalIgnoreCase)).ToList();
refer here for documentation

What is the best way to write queries in Entity Framework

What is best way to write query performance wise. e.g. i can write query to get all employes on specific last name as follow
ObjectQuery<Employee> queryEmp =
context.CreateQuery<Employee>(
"Select value e from Employees AS e Where e.LastName = #lastName",
new ObjectParameter("lastName", typeof(String)) { Value = "Farooqi" });
ObjectResult<Employee> results = query.Execute(MergeOption.AppendOnly);
OR
var v = from e in context.Employees where e.LastName == "Farooqi" select e;
OR
context.Employees.Where(e => e.LastName == "Farooqi");
OR
context.Employees.Where("LastName = #lastName", new ObjectParameter("lastName", typeof(String)) { Value = "Farooqi" });
My question is this that which method for querying is best.
What i am confused with is that i think (but not sure) that using last three methods other than the first one will fetch all records of employee from database then by enumerating all records those will be returened which fulfill the specified where condition, so i think last three ways will take more time than the first one so i used only first one.
But what is the best one in actual i dont know.
Do all method only fetch records form database which fulfill the were condition or fetch all records from db and then enumrated to return filtered records at applicaion end ?
There is little difference; the 2nd/3rd have the advantage of enforcing type correctness at compile-time, since the expression-tree won't compile if LastName doesn't exist or is (say) an int - avoids typos and the issue of "magic strings".
Re your supposition about bringing back everything; no. The 2nd/3rd compile to expression trees, which can be de-constructed and used to create the correct SQL (performing the filter at the server). Very clever, but often misunderstood. The key point is that this is Queryable.Where (taking an Expression<Func<T, bool>>), not Enumerable.Where (taking a Func<T, bool>). Feel free to perform a trace.
Likewise, there is little difference between the 1st/4th - both will filter at the server.

LINQ: When to use Compiled Queries?

I'd like some expert advice on this. I've used compiled queries before, but for this particular case, i'm not sure whether it's appropriate.
It's a search form where the query changes and is dependent on what is being searched on.
static Func<DBContext, int, IQueryable<Foo>> Search = CompiledQuery.Compile(
(DBContext db, int ID) =>
db.Person
.Where(w => w.LocationID = ID)
.Select(s =>
new Foo
{
Name = s.PersonName,
Age = s.Age,
Location = s.LocationName,
Kin = s.Kin
}));
Now if someone fills in the search box, i want to extend the query by adding another Where statement to the query:
var query = Search(context, 123);
query = query.Where(w => w.Name.Contains(searchString));
So my question is, is it returning all the results where LocationID == 123, then checking the results for a searchString match? Or is it actually extending the compiled query?
If it's the former (which i suspect it is), should scrap the CompiledQuery and just create a method that extends the query then return it as a list?
Also, what are the best practices for CompiledQuery usage and is there a guideline of when they should be used?
Note: I'm using the above in an ASP.NET website with Linq to SQL. Not sure if that makes any difference.
Thanks
The problem is that the compiled query is set in stone; it knows what SQL it will run against the database. The lambda expression is lazy loaded however, and cannot modify the compile query as it is being run during run time. The bad news is that it will return all of the records from the database, but it will query those records in memory to further refine them.
If you want to compile the query then I would suggest writing two queries with different signatures.
As far as I know, it is good practice to compile your query once, that is the whole point of pre-compiled query(and that's why your pre-compiled query is static), it saves time to compile that query into SQL. If it extend that pre-compiled query, then it is compiling that query again, which you loose gains.
Query result on result (your query variable) is no longer LINQ to SQL.
Just include your additional condition in your compiled query.
DB.Person.Where(w => w.LocationID == ID
& (searchString=="" || w.Name.Contains(searchString)))
If i am right then you need some dynamic where clause in linq. So for that i would suggest go this way
IEnumerable list;
if(condition1)
{
list = Linq Statement;
}
if(condition2)
{
list = from f in list where con1=con && con2=con select f;
}
if(condition3)
{
list = from n in list con1=con && con2=con select f;
}
I hope you got my words.

Conditional shortcuts in LinqToSql query

Here's a little LinqToSql GOTCHA:
// Returns the number of counties in a state,
// or all counties in the USA if the state is null
public static int CountCounties(State s) {
var q =
from cy in County.GetTable() // my method to get the ITable
where (s == null || s.Code == cy.StateCode) // shortcut OR operator, right...?
select cy;
return q.Count();
}
Guess what - if you pass a null State object to this method, you get a null reference exception! It seems that LinqToSql doesn't use the || shortcut operator as a shortcut!
Answer credit goes to whoever proposes the best explanation & workaround for this.
If it's linq to sql then remeber that Linq is just parsing your query into SQL.
It is therefore sending both of your where clauses to the database, hence the exception. I dont find this surprising really, though it is arguably wrong.
You will just have to do an independant check.
if (!string.isNullOrEmpty(state.statecode)
q = q.where( s => s.code == state.statecode
This is not related to LINQ in general. In this case, the LINQ-to-SQL provider tries to parse the your lambda expression and make it a TSQL query. It cannot make too many assumptions based on your expression since it's trying to delegate most of the work to the database.
Long story short, the provider simply cannot translate it to SQL.

Why is the SQL produced by LINQ-to-Entities so inefficient?

The following (cut down) code excerpt is a Linq-To-Entities query that results in SQL (via ToTraceString) that is much slower than a hand crafted query. Am I doing anything stupid, or is Linq-to-Entities just bad at optimizing queries?
I have a ToList() at the end of the query as I need to execute it before using it to build an XML data structure (which was a whole other pain).
var result = (from mainEntity in entities.Main
where (mainEntity.Date >= today) && (mainEntity.Date <= tomorrow) && (!mainEntity.IsEnabled)
select new
{
Id = mainEntity.Id,
Sub =
from subEntity in mainEntity.Sub
select
{
Id = subEntity.Id,
FirstResults =
from firstResultEntity in subEntity.FirstResult
select new
{
Value = firstResultEntity.Value,
},
SecondResults =
from secondResultEntity in subEntity.SecondResult
select
{
Value = secondResultEntity.Value,
},
SubSub =
from subSubEntity in entities.SubSub
where (subEntity.Id == subSubEntity.MainId) && (subEntity.Id == subSubEntity.SubId)
select
new
{
Name = (from name in entities.Name
where subSubEntity.NameId == name.Id
select name.Name).FirstOrDefault()
}
}
}).ToList();
While working on this, I've also has some real problems with Dates. When I just tried to include returned dates in my data structure, I got internal error "1005".
Just as a general observation and not based on any practical experience with Linq-To-Entities (yet): having four nested subqueries inside a single query doesn't look like it's awfully efficient and speedy to begin with.
I think your very broad statement about the (lack of) quality of the SQL generated by Linq-to-Entities is not warranted - and you don't really back it up by much evidence, either.
Several well respected folks including Rico Mariani (MS Performance guru) and Julie Lerman (author of "Programming EF") have been showing in various tests that in general and overall, the Linq-to-SQL and Linq-to-Entities "engines" aren't really all that bad - they achieve overall at least 80-95% of the possible peak performance. Not every .NET app dev can achieve this :-)
Is there any way for you to rewrite that query or change the way you retrieve the bits and pieces that make up its contents?
Marc
Have you tried not materializing the result immediately by calling .ToList()? I'm not sure it will make a difference, but you might see improved performance if you iterate over the result instead of calling .ToList() ...
foreach( var r in result )
{
// build your XML
}
Also, you could try breaking up the one huge query into separate queries and then iterating over the results. Sending everything in one big gulp might be the issue.

Categories