Linq to Entity compare two string in Where clause - c#

I've got an error:
LINQ to Entities does not recognize the method 'Int32 ToInt32(System.String)' method, and this method cannot be translated into a store expression.
The piece of code:
plist= plist.Where(p => Convert.ToInt(p.Period) >= syslockPeriod);
p.Period example: 201206
pList is IQueryable. p.Period is string typed. sysLockPeriod is int.
How to fix it?

LINQ to entities will try to translate Convert.ToInt32() into SQL instructions, because it's not one of the known methods it can translate then it'll generate that error.
You have some workaround but for all of them you have to change your code. Let's see what you can do (in order of preference, for me).
Convert Period property/field to the proper type. If it's an integer type then why you store it in your DB as a string?
Create a function (in your database) to perform the conversion and use a calculated property (or a view). LINQ to Entities will now have a true column of the proper type (no need to convert) or a function to call (on SQL side) to do the conversion. See this example on MSDN about how to call custom database functions.
Convert IQueryable to IList with ToList() before Where(), now the where clause will be executed locally and not on the database (this may be something terrible to do if the list is pretty big).

Do not convert that syslockPeriod to a string outside the LINQ query. It would help to get rid of the error (if you also remove the "Convert.ToInt"), but would return wrong results. This would give a "true" result: "12" < "2".
The correct solution would be to convert that string-column "Period" to an integer column.

This is a common problem in LINQ because you cannot use normal functions in the LINQ expression. (This allows LINQ to do lazy evaluation and reduces state related problems that can occur from invoking functions). Fortunately, we can work around this problem by creating a business object to do the conversions for you in the accessors, or use Linq to SQL which will convert it.
I prefer the former, as it is good practice to create the business objects as it encouraged reuse.
See the excellent post at http://mosesofegypt.net/post/LINQ-to-Entities-Workarounds-on-what-is-not-supported.aspx for samples.

Related

Can a linq query EVER change its data source, i.e. a dictionary's content?

It seems to me that Linq can only -query- a given data source, that is, it browses through it and returns stuff from it as necessary, but doesn't change anything. However, the wording in some of the answers I found on the matter are making me doubt this understanding. Is my understanding correct in all circumstances? Can a linq query -ever- change the content of the data source it is associated to?
Can a linq query -ever- change the content of the data source it is associated to?
Yes, though this is a bad idea.
LINQ queries (at least with LINQ to Objects) work by using delegates for the filter or mapping operations. In general, these shouldn't ever cause side effects, but that doesn't mean that they couldn't do so if you forced them to. The actual LINQ methods won't change the data, but they work via delegates that are just code you provide, which means that code could do anything.
Note that this would, in general, be a bad idea.
For example, say you were doing a query over a collection of Person instances:
var results = people.Where(p => p.Name == "Foo")
.Select(p =>
{
// This is evil, don't do it!
p.Name = "Bar";
return p;
});
That being said, this is unlikely to work with LINQ against an IQueryable<T>. In that case, the lambda you provide will be converted into an Expression, which will in turn need to be translated by the provider into some other form (ie: Entity Framework converts this to SQL). As such, you would only be able to create side effects if the provider was written in a way that this would translate into a meaningful form, which is unlikely to be the case.

The null value cannot be assigned to a member with type decimal which is a non-nullable value type

An exception occurs when the following IQueryable is enumerated:
from record in dataContext.SomeTable
select Convert.ToDecimal(record.nullableDecimalColumn);
The error is an InvalidOperationException:
The null value cannot be assigned to a member with type decimal which is a non-nullable value type
The documentation for Convert.ToDecimal says that it converts null to 0, so it looks like it should work correctly.
If you wrote Query like this
tot_vat_amt = _pd.Where(x => x.VAT == 4m).Sum(x =>x.amount)
Replace with
tot_vat_amt = _pd.Where(x => x.VAT == 4m).Sum(x =>(double?)x.amount)
Hope this will help you
LINQ to SQL wasn't translating the ToDecimal method equivalently; it wasn't tolerating NULL. I fixed this by using GetValueOrDefault instead of Convert.ToDecimal:
from record in dataContext.SomeTable
select record.nullableDecimalColumn.GetValueOrDefault();
This caused the correct SQL to be produced, so the exception no longer occurred.
Here is my understanding of why this happens. LINQ to SQL and Entity Framework provide face-value semantic translation rather than literal translation. In this example, Convert.ToX is translated directly to CONVERT or CAST in SQL. This is the SQL equivalent translation, but not literal because it does not include the fine details of how .NET Convert.ToX operates. Specifically, the .NET one converts nulls to default values.
This is a symptom of the fact that the code didn't express what its author (who wasn't me) was really trying to do, which was convert nulls to default values rather than convert between data types.
In my opinion, this is also a symptom of IQueryable being a leaky and unreliable abstraction. I personally think it would be better not to use it in the first place and instead use something that's designed better such as a normal/fluent API. I think IQueryable completely violates the interface segregation principle because it allows an unlimited range of queries to be used despite only a limited subset being supported.

How can I order by a derived property in linq to sql?

I have a property called Total that is derived from other values on my data object. When I try to use this property in an order by statement in linq to sql I get: The member '...' has no supported translation to SQL. Which makes sense but is there a work around for this scenario? Thanks!
You could invoke the query and than do your OrderBy() clause.
var items = context.Tables.ToList().OrderBy(x=>x.Total);
You can do this since after you invoke .ToList() you will be using linq to objects.
As Broken mentions this might not work in all cases, another possible solution would be to reproduce your total calculation in your .Select()
note, my syntax might be off a bit, dont have VS with me :)
var items = context.Tables.Select(t=> new {t.Item1, Total=(t.Price + t.Tax)})
.OrderBy(t=>t.Total);
Now granted with this type of projection you wont end up with a Table any more but might be an option.

Best approach to dynamically filter .Net objects

The project I'm working currently on has a way to define a filter on objects from a database.
This filter is a pretty straightforward class containing criteria that will be combined to produce a SQL where clause.
The goal now is to use this class to filter .Net objects as well. So for example the filter might specify that the title property of the object that it is applied to must contain some user-defined string.
What are ways to approach this problem? What should the filter return instead of the sql where-clause and how can it be applied to the object? I've been think about this for hours and don´t yet have even a slight idea how to solve this. Been thinking about reflection, dynamic code execution, building expressions but still haven´t found a starting point.
It depends on what all the use-cases are :)
If your DB code could use LINQ, then I might consider returning an Expression<Func<YourEntity,bool>>, as this can be applied via .Where to both DB-based LINQ and LINQ-to-Objects - in the latter case simply by calling:
var filtered = original.AsQueryable().Where(filter);
(DB code is typically already queryable, so no AsQueryable is needed).
One bad thing about this is that there is no guarantee that a particular query expression will work on every LINQ provider.
Alternatively, you would have to write either your own basic query language, or a basic tree-structure. And then write code to translate to both property-reflection and SQL. Lots of work.
One final thought is to just have two different query results, and keep the two thigs separate. So one SQL, one Predicate<T> or similar. There is a risk of them being out of sync, though.
If you want to do it a bit like the dynamically created SQL where clause, you could use Dynamic LINQ to achieve similar effects.

Lambda Expressions and Stored Procedures

I'm trying to mimic the LINQ Where extension method for my ADO.NET DAL methods.
Bascially, my aim is to have a single method that I can call. Such as:
Product p = Dal.GetProduct(x => x.ProductId == 32);
Product p2 = Dal.GetProduct(x => x.ProductName.Contains("Soap"));
I then want to dissect those Predicates and send the filter options to parameters in an ADO.NET Stored Procedure call.
Any comments greatly appreciated.
As #Daniel points out, this is far from simple. The solution outline is to let GetProduct take an argument of type Expression<Func<Product, bool>>. You then have to traverse the parse-tree of this expression, generating the correct SQL for functions known and also decide how to handle unknown functions. There are basically two options for that:
Throw an error (as linq-to-sql does).
Skip it in the translation and then apply it on the returned result. The performance impact of this can of course be huge if a lot of data is retreived just to be filtered out.
It would be a fun exercise to do it - but I can hardly see a way to justify it in the real world, when there are already linq2sql, linq2entities and linq2NHibernate that does the job.
In addition to Anders's answer, I just want to mention that you can analyze the expression tree by using an expression visitor. To do that, you can inherit the ExpressionVisitor class (it's new in .NET 4, but you can find a 3.5 implementation in LinqKit) and override the methods you want to analyze each node.
You might also be interested in those links :
Building a LINQ Provider
Walkthrough: Creating an IQueryable LINQ Provider

Categories