I'm trying to perform a LIKE clause in an entity query. The examples I've seen use dynamic linq to do this kind of thing, but my code...
var query = context.StudySet
.Where("it.PatientName LIKE #patientName", new ObjectParameter("patientName", patientName);
...gives me a System.Linq.Dynamic.ParseException with
Additional information: Expression of type 'Boolean' expected
context is a DbContext from EF 6 code-first, patientName is a string
Please tell me what's wrong with my code?
if you want use DynamicLINQ you need change your code like this
var query = context.StudySet.Where("it.PatientName.Contains(#0)", patientName);
because DynamicLinq can't parse LIKE operator
I've realised my mistake.
I had assumed the method to pass the query was part of Dynamic Linq but actually it's just a variant of the standard Where method on ObjectQuery. If I get the ObjectContext from my (code first) DbContext it's all good.
ObjectContext objectContext = ((IObjectContextAdapter)context).ObjectContext;
ObjectSet<Study> studySet = objectContext.CreateObjectSet<Study>();
var query = studySet.
Where("it.PatientName LIKE #patientName", new ObjectParameter("patientName", patientName));
I don't know of a way to use like with a LINQ query, but you could use a raw SQL query:
var query = context.StudySet.SqlQuery(
"select * from StudySet where PatientName LIKE #patientName",
new SqlParameter("#patientName", patientName));
Related
I'd like to use an action filter to translate an Odata uri to a Linq expression. I'm doing this because i'm using the resulting expression to query nonSQL line of business systems. In the WCF web api this was trivial because the translated query was appended as a property of the the request object, as such:
var query = (EnumerableQuery)request.Properties["queryToCompose"];
That seems to have disappeared. Are there any public api's i can use to accomplish this?
I've been trying something similiar.. While not perfect, you can grab the OData expressions directly from the query string and build the LINQ expression manually:
var queryParams = HttpUtility.ParseQueryString( ControllerContext.Request.RequestUri.Query );
var top = queryParams.Get( "$top" );
var skip = queryParams.Get( "$skip" );
var orderby = queryParams.Get( "$orderby" );
And the apply that directly to your IQueryable or whatever you're using for the filtering. Not nearly as useful, but its a start.
So as it turns out the query has changed keys in the request property collection. It also seems that the internal filter that parses the query runs after the custom filters and thus doesn't add the query value. To get the translated query, call the following inside the controller action.
(EnumerableQuery<T>)this.Request.Properties["MS_QueryKey"];
Check out Linq2Rest. It solves this problem.
How can i convert linq to object query or any other Func delegate to string like sql statements
for example
var cat_list = new List<Cat> { ... };
var myquery = cat_list.Where(x => x.Age > 2 && x.Name.Contains("Kitty"));
Now myquery is IEnumerable<Cat>. how can i convert this to simply something like this
"Age > #p1 AND Name LIKE #p2"
how can i achieve this ??
Doing something like that is not simple. Have a look at the series of articles Building an IQueryable provider by Matt Warren. All the code he uses is available as a library too. That should help you get started.
You could write an expression tree parser and generate the sql. Your description contains a fault - myquery isn't IQueryable<Cat>, it is an IEnumerable<Cat>. As you tagged it correctly, this is linq-to-objects, not linq-to-sql. There is no information in the calls to construct a query.
Check out the method DataContext.GetCommand() which is passed an IQueryable object and returns the DbCommand object that corresponds to the query. The CommandText property of the DbCommand object shows the text of the query.
I think we are basically looking for a extension method that could take in an IQueryable and return an IQueryable based on an entire query statement and not just the where statement.
Example of what we would like for a Search Method:
IRepository<Person> repository = new Repository<Person>();
var results = repository.GetQuery().Include("Names").Search([dynamic linq here]);
We currently have where we build a dynamic linq statement inside the where method
IRepository<Person> repository = new Repository<Person>();
var results = repository.GetQuery().Include("Names").Where([dynamic linq here]);
The problem with that approach is that we want to do include SelectMany and Select on the actual dynamic linq query. You cannot use the SelectMany inside a Where method unless you are actually going into sub properties of sub properties. We would like to do something like the following dynamic linq statement.
SelectMany("Names").Where("LastName.Contains(#0)", "Smith").Select("Person")
We solved this issue without having to use a extension method. We were able to use a similar query that works inside a Where method.
So instead of...
SelectMany("Names").Where("LastName.Contains(#0)", "Smith").Select("Person")
We were able to get the same result with the following query that can be inside a Where method.
Where.("Names.Select(LastName).Contains(#0)", "Smith)
Then when just had to add a Contains Aggregate to the Dynamic Linq library.
http://blog.walteralmeida.com/2010/05/advanced-linq-dynamic-linq-library-add-support-for-contains-extension-.html
The SelectMany had sent us off on a wild goose chase!
Checkout this nuget package: NinjaNye.SearchExensions
It enables you to do something like the following:
var repository = new Repository<Person>();
var results = repository.GetQuery().Search(p => p.LastName, "Smith");
Connected to sql this will produce something smilar to the following:
SELECT [Extent1].[Id] AS [Id],
... [other properties],
[Extent1].[LastName] AS [LastName]
FROM [dbo].[Person] AS [Extent1]
WHERE ([Extent1].[LastName] LIKE N'%Smith%')
The query is built using expression trees so the result is clean.
Check out the source code here:
https://github.com/ninjanye/SearchExtensions/
Suppose I have a function call from EF like:
var result = context.myFunction();
the result type is ObjectResult<int?>. Then I want to use linq to get the single value.
How to write the linq?
Maybe something like this
result.SkipWhile(o => !o.HasValue).Take(1)
Don't know what's wrong here, when I run the application it says "Specified method is not supported" pointing at "var result in query" in foreach loop. Please help...
var query = from c in entities.Customer
select c.CustomerName;
List<string> customerNames = new List<string>();
foreach (var result in query)
{
customerNames.Add(result.ToString());
}
EDIT: using ToList() also gives the same error.
The reason for your error is scope, which is what the "method not supported" error is telling you.
This usually happens when using a Linq to [fill in the blank] ORM. So, I'm guessing your entities must be from an ORM tool, something like Entity Framework, and you are using something like Linq to Entities.
When using linq your query is not enumerated out until you access it, which for an ORM means hitting the database or other data repository. This delayed action can cause some strange behavior if you do not know it is there, such as this error.
But, you have local (non-linq) code and your query intertwined, so the linq to [] compiler does not know how to handle your local code when compiling the linq code. Thus the "method not supported" error - it is basically the same as referencing a private method from outside of the class, the method you called is unknown in the current scope.
In other words the compiler is trying to compile your query and hit the database when you do the result.ToString(), but does not know anything about the private variable of CustomerNames or the foreach method. The database logic and the local object logic have to be kept separate - completely resolve the database query results before using locally.
You should be able to write it like this:
var customerNames = entities.Customer.Select(c => c.CustomerName).ToList();
If you have to keep the foreach (for more complicated logic, not for this simple of an example) you still need to resolve the Linq to [] portion (by forcing it to enumerate the query results) prior to involving any non-linq code:
var query = from c in entities.Customer
select c.CustomerName;
var qryList = query.ToList();
List<string> customerNames = new List<string>();
foreach (var result in qryList)
{
customerNames.Add(result.ToString());
}
Can you try using just the ToList() method instead of the foreach?
List<string> customerNames = query.ToList();
If the problem is not ToString() as Gart mentioned my second suspicious falls in c.CustomerName. Is this a custom property in your partial class?
Also, the stacktrace of the exception must surly show what is the unsupported method.
Try removing .ToString() and see if this will work:
foreach (var result in query)
{
customerNames.Add(result);
}
Seems like that the root of the problem lies deep inside LINQ-to-SQL query translation mechanism. I suppose the translation engine tries to translate .ToString() into SQL and fails there.
try this
var query = from c in entities.Customer
select c.CustomerName;
List<string> customerNames = new List<string>();
query.ToList().ForEach(r=>customerNames.Add(r));