Is string functions used in linq queries breaks down into query expressions? - linq

I have the scenario, where i am using string equals method for comparison with the data in db and it is breaking down into query expressions, so how its working? Do Linq supports all c# methods in the queries or only string class methods.
var us = "uttams";
IQueryable<UserData> use = (from user in entity.Users
where user.UserName.equals(us)
select new UserData{ UserName = user.UserName }).AsQueryable<UserData>();
var name = use.FirstOrDefault().UserName;

There is a set of methods that are supported, and all the others are not supported (you should think about it as a whitelist).
CLR Method to Canonical Function Mapping
Boolean Equals(String a, String b) method is translated into = operator in SQL query.

Related

How can I use custom expressions in DevArt LINQ to Entities and also use query comprehension syntax?

I've got a situation where I need to use a custom expression in a LINQ to Entities query (because I want to have custom logic that L2E wouldn't otherwise understand:
var query = db.MyTable.Where(MyPredicateExpression)
But I'd rather use query comprehension syntax:
var query = from x in db.MyTable where [x matches the predicate of MyPredicateExpression]
I know this is possible, because L2E supports it in other places:
var query = from x in db.MyTable where x.Length > 10
How do they make that work?
Edit: I'm using devart's LinqConnect for Oracle, which may behave somewhat differently than Microsoft L2E.
Entity Framework and LINQ to SQL do not support this scenario, because the translation of MyPredicateExpression should be added to expression tree translator.
I recommend you to create a stored function performing the predicate check and add this function to DataContext. You will be able to use a query like the following in this case:
var query = from x in db.MyTable where context.MyPredicateFunction(x.Field) select x;
Update. Here is the updated query that takes into account your comments:
int[] values = new int[] { 1, 2, 3 };
var query = from x in db.MyTable where values.Contains(x.AuditState) select x;
Update 2. You can add a Queryable property to your context that will be obtaining the necessary set of MyTable objects as shown in the following example:
public partial class MyDataContext {
IQueryable<MyTable> GetSpecialTables {
get {
int[] values = new int[] { 1, 2, 3 };
return this.MyTables.Where(x => values.Contains(x.AuditState));
}
}
}
Replace MyDataContext with the actual name of your context.
If I understand the problem correctly, you can either use an extension method OR call a function that returns a bool.

how to use a method with 2 parameters in my lambda expression

I use linq to access a table from my DB using Entity Framework
MyDBEntities context = new MyDBEntities;
int id = 111;
var item = context.MyTable.Where(i => i.id == id).Single();
This works fine but now I create a method I wish to use instead of the id check:
bool AreNear(string Adress, object Adress)
I'd like to use that way
string adress = "...";
var item = context.MyTable.Where(i => AreNear(i.adress,adress) ).Single();
but I get an error at the execution saying I can't use the method in my query
is there a way to make it work?
Unfortunately, there is no way to make it work.
The reason for this is that the LINQ query isn't really executed as .NET code but it is translated into SQL by the EF provider. This EF provider doesn't know how to translate AreNear into SQL, so it fails.

Linq: Dynamic Query Contruction: query moves to client-side

I've been following with great interest the converstaion here:
Construct Query with Linq rather than SQL strings
with regards to constructing expression trees where even the table name is dynamic.
Toward that end, I've created a Extension method, addWhere, that looks like:
static public IQueryable<TResult> addWhere<TResult>(this IQueryable<TResult> query, string columnName, string value)
{
var providerType = query.Provider.GetType();
// Find the specific type parameter (the T in IQueryable<T>)
var iqueryableT = providerType.FindInterfaces((ty, obj) => ty.IsGenericType && ty.GetGenericTypeDefinition() == typeof(IQueryable<>), null).FirstOrDefault();
var tableType = iqueryableT.GetGenericArguments()[0];
var tableName = tableType.Name;
var tableParam = Expression.Parameter(tableType, tableName);
var columnExpression = Expression.Equal(
Expression.Property(tableParam, columnName),
Expression.Constant(value));
var predicate = Expression.Lambda(columnExpression, tableParam);
var function = (Func<TResult, Boolean>)predicate.Compile();
var whereRes = query.Where(function);
var newquery = whereRes.AsQueryable();
return newquery;
}
[thanks to Timwi for the basis of that code]
Which functionally, works.
I can call:
query = query.addWhere("CurUnitType", "ML 15521.1");
and it's functionally equivalent to :
query = query.Where(l => l.CurUnitType.Equals("ML 15521.1"));
ie, the rows returned are the same.
However, I started watching the sql log, and I noticed with the line:
query = query.Where(l => l.CurUnitType.Equals("ML 15521.1"));
The Query generated is:
SELECT (A bunch of columns)
FROM [dbo].[ObjCurLocView] AS [t0]
WHERE [t0].[CurUnitType] = #p0
whereas when I use the line
query = query.addWhere("CurUnitType", "ML 15521.1");
The query generated is :
SELECT (the same bunch of columns)
FROM [dbo].[ObjCurLocView] AS [t0]
So, the comparison is now happening on the client side, instead of being added to the sql.
Obviously, this isn't so hot.
To be honest, I mostly cut-and-pasted the addWhere code from Timwi's (slightly different) example, so some of it is over my head. I'm wondering if there's any adjustment I can make to this code, so the expression is converted into the SQL statement, instead of being determined client-side
Thanks for taking the time to read through this, I welcome any comments, solutions, links, etc, that could help me with this. And of course if I find the solution through other means, I'll post the answer here.
Cheers.
The big problem is that you're converting the expression tree into a delegate. Look at the signature of Queryable.Where - it's expressed in expression trees, not delegates. So you're actually calling Enumerable.Where instead. That's why you need to call AsQueryable afterwards - but that doesn't do enough magic here. It doesn't really put it back into "just expression trees internally" land, because you've still got the delegate in there. It's now wrapped in an expression tree, but you've lost the details of what's going on inside.
I suspect what you want is this:
var predicate = Expression.Lambda<Func<TResult, Boolean>>
(columnExpression, tableParam);
return query.Where(predicate);
I readily admit that I haven't read the rest of your code, so there may be other things going on... but that's the core bit. You want a strongly typed expression tree (hence the call to the generic form of Expression.Lambda) which you can then pass into Queryable.Where. Give it a shot :)

LINQ on System.Object (type known only at runtime using reflection)

I have a simlar requirement where in i have 3 main entities in ADO.NET entity model... I am building a framework wherein basedon incoming XML root element i have to create an instance of specific entity using reflection and set its properties..
But when it comes to child entities.. I am not able to use LINQ queries on it as the type is not known at design time. PropertyInfo.GetValue gives me an object on which i can not run LINQ queries (even when i typecast it to IQueryable or IEnumerable). I am not even able to typecast it at design time as that would be kind of hardcoding and will fail my generic framework purpose.
I tried to use dynamic keyword.. but on that too i can not write LINQ queries.. it gives a message that LINQ queries are not supported on dynamic dispatch model.!!!
Can someone help..
Regards Badal
Like #Yuriy Faktorovich recommended, dynamic LINQ may be your best shot.
Another option you have is to dynamically build expression trees and execute your expression via reflection. Keep in mind that this is not easy and may take a little time to wrap your head around the expression API, but for simple expression it's not too bad.
Example: Say you want to replicate this expression:
p => p.FirstName == firstName
You can build the expression tree as follows:
var myType = Type.GetType("Person"); // <-- Find your type based on XML
var firstName = "John";
var param = Expression.Parameter(myType, "p");
var firstNameProperty = Expression.Property(param, "FirstName");
var constantExpression = Expression.Constant(firstName);
var equalsExpression = Expression.Equal(firstNameProperty, constantExpression);
var lambda = Expression.Lambda(equalsExpression, param);
The lambda will have a runtime type of Expression<Func<Person,bool>> which you can then pass to any IQueryable implementation.
UPDATE
Then to dynamcially call some method on your IQueryable you can do something similar to the following:
var queryableType = typeof(Queryable);
var whereMethod = queryableType.GetMethod("Where", BindingFlags.Public | BindingFlags.Static);
var parameters = new object[] { query, lambda }; // query is your IQueryable object
var list = whereMethod.Invoke(null, parameters);

Linq expression subsonic 3.0.0.3

I want to 'build' a combined query for Subsonic 3.0.0.3, what is the best way for this?
I tried;
Expression<Func<Person, bool>> exp = p => true;
Expression<Func<Person, bool>> fContinent = p => p.ContinentID == 1;
Expression<Func<Person, bool>> fType = p => p.TypeID == 1;
exp = Expression.Lambda<Func<Person, bool>>(Expression.AndAlso(exp, fContinent), exp.Parameters);
exp = Expression.Lambda<Func<Person, bool>>(Expression.AndAlso(exp, fType), exp.Parameters);
var personList = Person.Find(exp);
But that will give the exception "The binary operator AndAlso is not defined ..."
I also tried using predicates but that will throw exceptions as well (Expression.Invoke is not supported).
In subsonic 2 I would have used the SqlQuery object, but I would like to know the proper way to do this in version 3 using linq / expressions.
Have you tried And instead of AndAlso?
The right way to do this is to combine the lambda expression bodies, like this:
exp = Expression.Lambda<Func<Person, bool>>(
Expression.And(exp.Body, fContinent.Body), exp.Parameters);
Even if And is supported by your query provider, you'll also need to replace the parameter references in fContinent's Body with references to the parameter defined in exp--as is, your two expression bodies (combined with And) reference two distinct parameters, each named p.
See my answer to this question for the cleanest method to replace expression parameters.
I asked this question, but I am using the combined query in subsonic just like you.
In short, you want to use a PredicateBuilder to build up the query. When you want to execute it in your subsonic object (assuming ActiveRecord), use code like this:
var predicate = /* Build up predicate with PredicateBuilder */;
var recs = SubsonicClass.All().Where(predicate.Compile()).ToList();

Resources