i am getting below error while applying filter condition to the LINQ to SQL table.
Is there a way to create the SQL query with Where condition in LINQ to SQL?
Error:
"Method 'Boolean Equals(System.String, System.String, System.StringComparison)' has no supported translation to SQL."
Below is the code
public IQueryable<DocumentReplacementPack> GetDocumentReplacementPack(string state,int typeID)
{
if (this.DataContext.DocumentReplacementPacks.Count() > 0)
**return this.DataContext.DocumentReplacementPacks.Where(d => string.Equals(d.State, state, StringComparison.InvariantCultureIgnoreCase));**
else
return this.DataContext.DocumentReplacementPacks;
}
No this is not an error, sadly this comes up a lot more than you think. Let's look at how linq converts expressions to sql from a high level
this.DataContext.DocumentReplacementPacks.Where(d => string.Equals(d.State, state, StringComparison.InvariantCultureIgnoreCase));
this will generate a sql call that looks similar to
select * from [DocumentReplacementPacks] where ??
now what is going to happen is the expression is going to get to the string.Equals call and since there is no REAL equivalent of string.Equals in sql, linq has no idea how to generate the sql string. Since string.Equals is a c# function and not a sql function. A really good example would be something like
public bool AreEqual(string one, string two){
return one.ToCharArray()[0] == two.ToCharArray()[0];
}
Now this is a very trivial example, but think if you had a linq expression like such:
return this.DataContext.DocumentReplacementPacks.Where(d => AreEqual(d.State, state));
How would you expect this to get translated? There is just no way, how would linq know exactly how to the function acts.
The way around this would be to switch to == since linq knows how to translate that.
return this.DataContext.DocumentReplacementPacks.Where(d =>d.State == state);
and let the database do the InvariantCultureIgnoreCase, now if that is not an option you will just have to read the data into memory and do the call.
this.DataContext.DocumentReplacementPacks.ToList().Where(d => string.Equals(d.State, state, StringComparison.InvariantCultureIgnoreCase));
but I do not advise that since reading a whole dataset into memory can be very very expensive.
* OFF TOPIC *
Also I was looking at your code and I highly recomment changing this.DataContext.DocumentReplacementPacks.Count() > 0)
to
this.DataContext.DocumentReplacementPacks.Any())
Explanation. I'm often disappointed with how people use linq without truly understanding IEnumerable/IQuerable but how else do you become a better developer?
MS SQL by default treats strings case insensitive, so you should use '==' which can be translated by LINQ2SQL
I have the following query, which is using Entity Framework.
Analytic firstSent = (from a in Repository.Query<Analytic>()
where a.EntityType == "Proposal" &&
a.EntityId == Program.ActiveProposal.Id &&
a.Marker == AnalyticMarker.EmailProposalUrl.ToString()
orderby a.TimestampUtc
select a).FirstOrDefault();
At run time, I get the following error:
LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression.
a.Marker is a string column, and AnalyticMarker.EmailProposalUrl is an enum value, and I want to compare that column against the name of that enum.
I understand that the conversion from an enum to a string is not supported by SQL, but why won't it resolve the value of this string and then pass the resulting string to SQL? That should work just fine.
Try this:
var emailProposalUrl = AnalyticMarker.EmailProposalUrl.ToString();
Analytic firstSent = (from a in Repository.Query<Analytic>()
where a.EntityType == "Proposal" &&
a.EntityId == Program.ActiveProposal.Id &&
a.Marker == emailProposalUrl
orderby a.TimestampUtc
select a).FirstOrDefault();
This other answer is explaining the reason why this could work as well..
The problem arises because ToString() isn't really executed, it is
turned into a MethodGroup and then parsed and translated to SQL.
Since there is no ToString() equivalent, the expression fails.
Well, in the places where C# will normally resolve tostring for you, it normally takes an object. Here, for example though, you're asking it to compare a string to an enum. Although C# COULD call tostring(), its not correct for it to do so.
Think about if it was int you were trying to compare against, rather than an enum. You can't compare the number 1 and a string. (Well, you can, but it involves assumptions, which is the point; the language is just trying to prod you into making the logic that little more explicit)
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);
in the following query
var restrictions = from p in dcTrad.quop_restricted_items
where p.entry_status == 'P' && p.batch == "PRODUCTION" && p.problem != null
from q in dcTrad.model_companies
where q.co_name != null && p.brimsec == q.primary_bsec
select new { Company = q.co_name, Restriction = p.comment ?? "Restricted without comments", Portfolio = p.problem };
I need to replace
p.brimsec == q.primary_bsec
with
p.brimsec.StartsWith ( q.primary_bsec )
but I get the following error:
Only arguments that can be evaluated on the client are supported for the String.StartsWith method
How can I make this work?
Unfortunately the LINQ to SQL translator is not smart enough to translate this code, but there's a trick that achieves the same:
p.brimsec.StartsWith ( q.primary_bsec )
Translates to:
p.brimsec.SubString(0, q.primary_bsec.Length) == q.primary_bsec
The LINQ to SQL translator handles this just fine, and the semantics are equivalent to StartsWith.
Frankly, I don't see why translating StartsWith properly for server-side arguments was so hard that the LINQ developers just decided to throw an error instead.
Basically the linq to sql does not know how to convert startswith to Sql. This is because internally at run time your linq is code generated to sql.
You may go about achieving this by creating a UDF (user defined function in sql) and using it from your linq statement.
The article is as below:
http://msdn.microsoft.com/en-us/library/bb399416.aspx
Andrew
I think the problem you're running into is that linq-to-sql has no translation of String.StartsWith into SQL. String.Contains does work, though - you'd need to go through your resultant collection and filter out the items that don't start with q.primary_bsec.
db.Albums.FirstOrDefault(x => x.OrderId == orderId)
or
db.Albums.FirstOrDefault(x => x.OrderId.Equals(orderId))
I'm going to try to convince you that:
The two methods you proposed give the same performance.
There are at least two non-performance related reasons you should prefer ==.
There is another separate improvement that you can make to your code to reduce the possibility of errors.
To see that the performance will be the same, look at the SQL generated in each case. This test program shows you how you can view the generated SQL:
int orderId = 4;
TextWriter textWriter = new StringWriter();
using (var dc = new DataClasses1DataContext())
{
dc.Log = textWriter;
Order o1 = dc.Orders.FirstOrDefault(x => x.OrderId == orderId);
Order o2 = dc.Orders.FirstOrDefault(x => x.OrderId.Equals(orderId));
}
string log = textWriter.ToString();
The SQL sent in each case is the same, as you can see by inspecting the log:
SELECT TOP (1) [t0].[OrderId], [t0].[CustomerID], [t0].[Date], [t0].[Description]
FROM [dbo].[Order] AS [t0]
WHERE [t0].[OrderId] = #p0
SELECT TOP (1) [t0].[OrderId], [t0].[CustomerID], [t0].[Date], [t0].[Description]
FROM [dbo].[Order] AS [t0]
WHERE [t0].[OrderId] = #p0
Regarding whether to use == or Equals, firstly I'd suggest using == for readability. This is the idiomatic way to compare two integers in C#.
Secondly with == you will get a compile time error if you give objects of different (incompatible) types. I assume that in your case order has type int, but let's assume that someone else wrote this code and accidentally made an error where order is a variable of type Order instead of an int. Now let's compare what would happen in each case:
Order order = new Order { OrderId = 4 };
x.OrderId.Equals(order) // This compiles, but you get an exception at runtime:
// Could not format node 'Value' for execution as SQL.
x.OrderId == order // Compile error: Operator '==' cannot be applied to
// operands of type 'int' and 'Order'
It is better to get compile time errors than runtime errors, so prefer to use == in this case.
Finally, if you only expect one result you should prefer to use SingleOrDefault instead of FirstOrDefault as the former will throw an exception if there are two matching objects found instead of just returning the first. This extra check will cost a tiny amount in performance but again allows you to catch errors earlier. If performance is a critical issue for you, instead of removing these safety checks you should consider fetching multiple objects from the database at once, not one object at a time.
So in summary I recommend that you use this:
Album album = db.Albums.SingleOrDefault(x => x.OrderId == orderId);
They will both be equivalent from a performance perspective. I tend to prefer == over .Equals() for readability, but the beauty of L2S is that you can use either one, depending on what type of object you have.
(And I'm assuming your second statement is on the orderId, and not the order object)
In most situations you should get the same result. However, there is a difference.
Using the operator Equals determines whether two Object instances are the same.
The operator == determines whether two Objects have the same value.
In this case, I use the == operator, so it's more readable.
It's almost same. If you want to check only the value then you should use
==
If you want check the value as well as if they are same instances or not use
Equals
But in both cases resulting time is almost same.