Linq to EF - Unsupported Functions - c#

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;

Related

Santax for Joins using Linq/lambda & Nhibernate

Originally I had this linq statement:
refusedZones = session.Query<ZoneBO>().Where(x => x.StateId == _config.RefusedStateId).ToList();
Works fine and I get my list with business objects. I now need to change this query, I still want my list of strongly typed business objects back, but I have to do a join with another table.
I have tested this SQL query and it works the way I want it to:
select z.ZoneName, z.ZoneSerial from zone z join transactionzone tz on z.ZoneId = tz.ZoneId where z.StateId = 3 and tz.StateId = 16
My question is how do I do this in linq with a Lambda expression? I assume it will start like this...
var refusedZones = session.Query<ZoneBO>().Join(.......expression here....).ToList();
Can anyone help me with the santax please, very new to linq, finding it confusing.
You will need to add a reference from Zone to TransactionZone. How have you setup your mappings?
Once you have a reference setup it is unnecessary to explicitly write the joins in LINQ.
You can do this:
session.Query<ZoneBO>()
.Where(x => x.State.Id == 3 && x.TransactionZone.State.Id == 16)
.ToList()

Entity Framework Filter "Expression<Func<T, bool>>"

I'm trying to create a filter method for Entity framework List and understand better the
Expression<Func<...
I have a Test Function like this.
public IQueryable<T> Filter<T>(IEnumerable<T> src, Expression<Func<T, bool>> pred)
{
return src.AsQueryable().Where(pred);
}
and if I do this:
context.Table.Filter(e => e.ID < 500);
or this:
context.Table.Filter(e => e.SubTable.Where(et => et.ID < 500).Count() > 0 && e.ID < 500);
it all works well.
But if I do this:
context.Table.Filter(e => e.SubTable.Filter(et => et.ID < 500).Count() > 0 && e.ID < 500);
or this:
context.Table.Where(e => e.SubTable.Filter(et => et.ID < 500).Count() > 0 && e.ID < 500);
I receive one error.
LINQ to Entities does not recognise the method ...Filter...
Why does it work in one case and not in the other? What should I change in the filter to make it work with related tables?
I prefer to stay away from other external libraries as what I want is to learn how it works and be able to use it in any scenario in future.
In the first two cases, the filter runs in the database correctly.
Jon and Tim already explained why it doesn't work.
Assuming that the filter code inside Filter is not trivial, you could change Filter so that it returns an expression EF can translate.
Let's assume you have this code:
context.Table.Where(x => x.Name.Length > 500);
You can now create a method the returns this expression:
Expression<Func<YourEntity, bool>> FilterByNameLength(int length)
{
return x => x.Name.Length > length;
}
Usage would be like this:
context.Table.Where(FilterByNameLength(500));
The expression you build inside FilterByNameLength can be arbitrarily complex as long as you could pass it directly to Where.
It's useful to understand the difference between Expression<Func<>> and Func<>.
An Expression e => e.ID < 500 stores the info about that expression: that there's a T e, that you're accessing the property ID, calling the < operator with the int value 500. When EF looks at that, it might turn it into something like [SomeTable].[ID] < 500.
A Func e => e.ID < 500 is a method equivalent to:
static bool MyMethod(T e) { return e.ID < 500; }
It is compiled as IL code that does this; it's not designed to be 'reconstituted' into a SQL query or anything else, only run.
When EF takes your Expression, it must understand every piece of it, because it uses that to build a SQL query. It is programmed to know what the existing Where method means. It does not know what your Filter method means, even though it's a trivial method, so it just gives up.
Why it works in one case and not in the adder?
Because EF doesn't really "know" about your Filter method. It has no understanding of what it's meant to do, so it doesn't know how to translate it into SQL. Compare that with Where etc, which it does understand.
The version where you call it directly on the initial table works because that way you don't end up with an expression tree containing a call to Filter - it just calls Filter directly, which in turn does build up a query... but one which EF understands.
I'd be very surprised if you could work out a way of getting your Filter method to work within an EF query... but you've already said that using Where works anyway, so why use Filter at all? I'd use the Where version - or better yet, use the Any overload which takes a predicate:
context.Table.Filter(e => e.SubTable.Any(et => et.ID < 500) && e.ID < 500);

Linq to SQL - Query

I am trying to mimic below statement in Linq to SQL.
WHERE (rtrim(posid) like '%101' or rtrim(posid) like '%532')
I statement basically determine if posid ends with 101 or 532. In the above example I am only making 2 comparisons but their could be 1 to N comparisons all joined with OR. I store the comparison values (101,532,...) in a generic list that I send to my Linq to SQL method.
I have tried to mimic above SQL using a where clause unsuccessfully (example below):
var PosNum = new List<string>();
PosNum.Add("101");
PosNum.Add("532");
var q = (from a in context.tbl_sspos select a);
q = q.Where(p => PosNum.Contains(p.posid.Trim()));
The issue with the above where clause is that it tries to do an exact match rather I want an ends with comparison.
How would I mimic the SQL statement in Linq to SQL.
Thank You in advance for any help / advice you can provide.
I would use String.EndsWith();
This will check the end of the string rather than entire contents of it.
var q = (from a in context.tbl_sspos select a);
q = q.Where(p => p.posid.EndsWith("102") || p.posid.EndsWith("532"));
In EF 4 you can use the StartsWith / EndsWith methods by now. Might also work in LINQ to SQL.
UPDATE
Just realized that you are trying todo this against multiple values (PosNum), I don't think that this is directly supported currently. You can however concatenate multiple Where()clauses to get the result.
UPDATE 2
As AdamKing pointed out concatenating the where clauses was filtering against all PosNum values, here is the corrected version:
var baseQuery = (from a in context.tbl_sspos select a);
IEnumerable<YourType> q = null;
foreach(var pos in PosNum)
{
if(q == null)
q = baseQuery.Where(a => a.posid.EndsWith(pos));
else
q = q.Union(baseQuery.Where(a => a.posid.EndsWith(pos)));
}
This is not as pretty anymore, but works nonetheless.

Dynamically Building a List of Func<t,t> - then applying to a linq query

Not sure if this is the best approach, however here are my thoughts
I am using Entity Framework Data Model v 4.1 - i'm trying to build a where statement dynamically so that I dont have to query the db everytime, instead i can build a "list of" conditionals, then apply them all at once so the db is only queryed once as opposed to everytime i add my new conditional - if that makes sense...
here is what i have
List<Func<Order, bool>> orderFunctions = new List<Func<Order, bool>>();
if (this.LoggedInUser.UserId == 9)
{
Func<Order, bool> deleg = o => o.Status.Equals(OrderStatus.NewOrder);
orderFunctions.Add(deleg);
}
else if (this.LoggedInUser.UserId == 22)
{
Func<Order, bool> deleg = o => o.AssignedToUserId.Equals(22);
orderFunctions.Add(deleg);
}
List<Orders> orders = Entities.Orders.Where( Some How Apply my Order Functions List Here ).ToList();
I'm not sure if i'm even taking the right approach here - hopefully this makes sense - any guidance, sample code would be fantastic, i've having a heck of a time finding examples / tutorials for this online
You can do this just by calling Where multiple times:
IQueryable<Order> query = Entities.Orders;
if (this.LoggedInUser.UserId == 9)
{
query = query.Where(o => o.Status.Equals(OrderStatus.NewOrder));
}
else if (this.LoggedInUser.UserId == 22)
{
query = query.Where(o => o.AssignedToUserId.Equals(22));
}
List<Order> orders = query.ToList();
Until you start trying to retrieve the results, it won't contact the database.
If you really want to create a list, you'd need to create a List<Expression<Func<Order, bool>>> - they have to be expression trees rather than delegates, so that the Entity Framework can deal with them. Then you could just do:
foreach (var predicate in predicates)
{
query = query.Where(predicate);
}
Or you could use PredicateBuilder to build up a single expression tree.
Jon gave - of course - the answer how to do this better.
But for your original point, and why this won't work:
It is not dificult to apply the hole list (just do
x => orderFunctions.All(f => f(x))
) but you will not get any SQL-love from this - meaning you will get an error because EF cannot know what to do with the all (or whatever you will code there).
You would have to query all entries (with ToList, or ToArray) and after this it would work ... but without performance ;)

Why do LINQ to Entities does not recognize certain Methods?

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});

Categories