Why do LINQ to Entities does not recognize certain Methods? - c#

Why cant I do this:
usuariosEntities usersDB = new usuariosEntities();
foreach (DataGridViewRow user in dgvUsuarios.Rows)
{
var rowtoupdate =
usersDB.usuarios.Where(
u => u.codigo_usuario == Convert.ToInt32(user.Cells[0].Value)
).First();
rowtoupdate.password = user.Cells[3].Value.ToString();
}
usersDB.SaveChanges();
And have to do this:
usuariosEntities usersDB = new usuariosEntities();
foreach (DataGridViewRow user in dgvUsuarios.Rows)
{
int usercode = Convert.ToInt32(user.Cells[0].Value);
var rowtoupdate =
usersDB.usuarios.Where(u => u.codigo_usuario == usercode).First();
rowtoupdate.password = user.Cells[3].Value.ToString();
}
usersDB.SaveChanges();
I must admit it is a more readable code but why cant this be done?

The thing about it is that LINQ queries are transformed by the compiler into an expression tree. This expression tree is then converted into T-SQL and passed to the server. LINQ to SQL maps certain methods like String.Contains to the T-SQL equivalents.
In the first example, LINQ apparently does not map Convert.ToInt32 to anything and the exception is thrown. The reason it works in your second example is because the Convert.ToInt32 call is done outside of the query so it isn't part of the expression tree and doesn't need to be converted to T-SQL.
This MSDN page describes how LINQ to SQL translates various data types, operators, and methods into T-SQL. (Although the documentation does suggest Convert.ToInt32 is supported so I'm not sure what else might be going on here.)
Sorry just realized this is ADO.NET Entity Framework, not LINQ to SQL. This page lists the ADO.NET Entity Framework mappings. It is a bit more restrictive, mostly because it needs to work with multiple providers.

Because your LINQ to Ent. doesn't compile the query into MSIL with all the meta data, but simply translates the query into a few extantion methods and is bounded to lambda parsing abuilities of the languge. That means that
this code:
var results = from c in SomeCollection
where c.SomeProperty < someValue * 2
select new {c.SomeProperty, c.OtherProperty};
is the same as this:
var results =
SomeCollection
.Where(c => c.SomeProperty < someValue * 2)
.Select(c => new {c.SomeProperty, c.OtherProperty});

Related

Convert LINQ method syntax with method withing .Select() to LINQ query syntax

I currently have the following code:
dataSource.Where(row => row.Value == 1)
.Select(row => {row["Text"] = translatedText; return row;})
.Single();
So my goal is to select the DataRow with "Value=1" and at the same time set the value in the "Text"-column to some other value (in my case a string-variable transalatedText).
This already works fine with the method chain mentioned above but I generally prefer the LINQ syntax. Is there a possibility to translate this method chain to LINQ?
My problem is that I do not know how to translate the function in the Select-method to LINQ-format. I dont want to create a new DataRow but want to really edit the selected one. (So I don't want to use from x in y where z select new DataRow(...) but to really edit my x if possible)
Thanks!
Is there a possibility to translate this method chain to LINQ?
(By "to LINQ" I believe you mean "to query expression syntax".)
Not directly, no. Effectively, you can only convert expression-bodied lambda expressions into query syntax. There's a good reason for that: LINQ is designed not to have side effects, whereas your "query" does have side-effects.
I would personally write your code like this instead:
var row = DataSource.Single(row => row.Value == 1);
row["Text"] = translatedText;
That neatly separates the querying from the side-effect. If you really, really want to use query expression syntax, you could write:
var query = (from row in DataSource
where row.Value == 1)
select HorribleMutatingMethod(row)).Single();
...
private DataRow HorribleMutatingMethod(DataRow row)
{
row["Text"] = translatedText;
return row;
}
... but please don't.

lambda equivalent to sql update with joins

I have 2 sets of data.
What would be the lambda syntax equivalent to this sql update statement ?
UPDATE Customers1
SET Customers1.Email = Customers2.Email
JOIN Customers2 ON Customers1.ID = Customers2.ID
Lambdas are just a way of writing anonymous methods: x => { body }. I assume you actually mean LINQ.
There is no equivalent, because the Q in LINQ stands for query. LINQ queries data, it doesn't change it.
As DanielHilgarth said just to use lambda or even LINQ is not enough here.
I assume you'd need something like:
foreach(var customer1 in customers1) {
var customer2 = customers2.FirstOrDefault(c2 => customer1.ID.Equals(c2.ID));
if (customer2 != null) customer1.Email = customers2.Email;
}
So, lambda is a chunk of the whole implementation.

Linq to EF - Unsupported Functions

I'm making a query with Linq, backed by an Entity Framework datasource.
I'm getting the following error:
LINQ to Entities does not recognize the method 'Double Sqrt(Double)'
method, and this method cannot be translated into a store expression.
Here's a simplified version of my function (my version is more complex and uses ACos, sin, cos and other C# Math class functions).
var objects =
from n in context.Products.Where(p => p.r == r)
let a = Math.Sqrt((double)n.Latitude)
where a < 5
orderby a
select n;
return objects.Take(100).ToList();
I think the problem may be related to the situation that Linq to EF (and a SQL datasource) has a limited set of supported function compared to Linq to SQL. I'm relatively new to this so I'm not 100% sure.
Can anyone give me a pointer in the right direction?
Cheers,
Try SquareRoot function defined in SqlFunctions
var objects =
from n in context.Products.Where(p => p.r == r)
let a = SqlFunctions.SquareRoot((double)n.Latitude)
where a < 5
orderby a
select n;
return objects.Take(100).ToList();
If you start of learning LINQ with LINQ-to-objects, you'll run into this a lot once you start using LINQ-to-Entities.
You can do pretty much anything that will compile in LINQ-to-objects, because LINQ-to-objects translates into code when compiled.
LINQ-to-Entities (and LINQ-to-SQL) translates into expression trees. So, only the syntax that that specific LINQ provider allowed for is valid. In my first "for real" LINQ-to-Entities expression, which compiled just fine, I ran into this error about 5 times, as one by one I removed code that wasn't handled by LINQ-to-Entities.
So when you see this, it's normal and common. You need to find another way each time.
You could avoid the problem with a logical equivalent:
var objects =
from n in context.Products.Where(p => p.r == r)
where (double)n.Latitude < 25
orderby a
select n;
return objects.Take(100).ToList();
You could also pull all the data to the client and then run your code using LINQ-to-objects:
var objects =
from n in context.Products.Where(p => p.r == r).ToList()
let a = Math.Sqrt((double)n.Latitude)
where a < 5
orderby a
select n;
return objects.Take(100).ToList();
Finally, you should be able to do this math on the server. Check out the System.Data.Objects.SqlClient.SqlFunctions SqlFunctions Class. These functions will translate into the expression. This in particular looks like it might be the ticket.
Please try
var objects =
from n in context.Products.Where(p => p.r == r)
let a = Math.Pow((double)n.Latitude, 0.5)
where a < 5
orderby a
select n;

Using "Match" in a Linq statement

I have a table that has two records (there will be many at runtime). The deviceId of the records are, “DEVICE1” and “DEVICE2”. I want to use a regular expression to extract records.
The code below compiles but fails to return a result. When I hover the cursor on the “devices.ToList()” statement I get the following error:
base {System.SystemException} = {"LINQ to Entities does not recognize the method 'System.Text.RegularExpressions.MatchCollection Matches(System.String)' method, and this method cannot be translated into a store expression."}”
Can anyone show me how I can modify my query so that this would return records based on the expression?
filterText = #"DEVICE.";
Regex searchTerm = new Regex(filterText);
using (var ctx = new MyEntities())
{
var devices = from d in ctx.Devices
let matches = searchTerm.Matches(d.DeviceId)
where matches.Count > 0
select ((Device)d);
return devices.ToList();
}
I don't believe you can use regular expressions with LINQ to Entities. However, it looks like you're just trying to find devices which start with "DEVICE", so the query would be:
return ctx.Devices.Where(d => d.DeviceId.StartsWith("DEVICE"))
.ToList();
EDIT: If you actually need the flexibility of a regular expression, you should probably first fetch the device IDs (and only the device IDs) back to the client, then perform the regular expression on those, and finally fetch the rest of the data which matches those queries:
Regex regex = new Regex(...);
var deviceIds = ctx.Devices.Select(d => DeviceId).AsEnumerable();
var matchingIds = deviceIds.Where(id => regex.IsMatch(id))
.ToList();
var devices = ctx.Devices.Where(d => matchingIds.Contains(d.DeviceId));
That's assuming it would actually be expensive to fetch all the data for all devices to start with. If that's not too bad, it would be a simpler option. To force processing to be performed in process, use AsEnumerable():
var devices = ctx.Devices.AsEnumerable()
.Where(d => regex.IsMatch(d.DeviceId))
.ToList();
You should always remember that your LinqToEntities queries must be translated to SQL queries. Since SQL Server has no support for regular expressions, this can not work.
As suggested in the comment by Paul Ruane, StartsWith will work. This can be translated by LinqToEntities into WHERE DeviceId LIKE 'DEVICE%'.
If StartsWith isn't enough because you may need to look for strings in the middle of database columns, Contains will also work:
var devices = from d in ctx.Devices
where d.DeviceId.Contains("DEVICE")
select d;
This will result in the following: WHERE DeviceId LIKE '%DEVICE%'.
Remember when using Entity Framework or Linq to Sql that your query ends up being translated to SQL. SQL doesn't understand your regular expression object, and can't use its matches on the server side. To use your RegEx easily you could instead retrieve all the devices from the server first, and then use your existing logic. e.g.
using (var ctx = new MyEntities())
{
var devices = from Device d in ctx.Devices select d;
// Retrieve all the devices:
devices = devices.ToList();
devices = from d in devices
let matches = searchTerm.Matches(d.DeviceId)
where matches.Count > 0
select ((Device)d);
return devices.ToList();
}
This does carry the cost of retrieving more data than you need, potentially much more. For complex logic you may want to consider a Stored Procedure, which could potentially use the same RegEx via CLR functions.
LinqToEntities does not support pushing Regex's down to the database. Just do Contains (which gets converted to sql... where DeviceId Like '%DEVICE%').
filterText = #"DEVICE.";
using (var ctx = new MyEntities())
{
var devices = from d in ctx.Devices
d.DeviceId.Contains(filterText)
select d;
return devices.ToList();
}

Lambda syntax in linq to db4o?

I know the following is possible with linq2db4o
from Apple a in db
where a.Color.Equals(Colors.Green)
select a
What I need however is something that allows me to build my query conditionally (like I can in other linq variants)
public IEnumerable<Apple> SearchApples (AppleSearchbag bag){
var q = db.Apples;
if(bag.Color != null){
q = q.Where(a=>a.Color.Equals(bag.Color));
}
return q.AsEnumerable();
}
In a real world situation the searchbag will hold many properties and building a giant if-tree that catches all possible combinations of filled in properties would be madman's work.
It is possible to first call
var q = (from Color c in db select c);
and then continue from there. but this is not exactly what I'm looking for.
Disclaimer: near duplicate of my question of nearly 11 months ago.
This one's a bit more clear as I understand the matter better now and I hope by now some of the db4o dev eyes could catch this on this:
Any suggestions?
Yes it's definitely possible to compose optimized LINQ queries using db4o. Granted that db is defined as follows:
IObjectContainer db;
Here is your query:
public IEnumerable<Apple> SearchApples (AppleSearchbag bag)
{
var query = db.Cast<Apple> ();
// query will be a Db4objects.Db4o.Linq.IDb4oLinqQuery<Apple>
if (bag.Color != null)
query = query.Where (a => a.Color == bag.Color);
return query;
}
In that case, the query will be executed whenever the returned enumerable is being iterated over.
Another possibility is to use the IQueryable mechanism, that has the advantage of being better recognized by developers:
public IQueryable<Apple> SearchApples (AppleSearchbag bag)
{
var query = db.AsQueryable<Apple> ();
// query will be a System.Linq.IQueryble<Apple>
if (bag.Color != null)
query = query.Where (a => a.Color == bag.Color);
return query;
}
In both cases, db4o will try to deduce an optimized query from the lambda expression upon execution, and if it fails, will fallback to LINQ to objects. The first one has the advantage of being more direct, by avoiding the queryable to LINQ to db4o transformation.

Categories