Extension Method To Take A Dynamically Built Search Expression? - linq

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/

Related

Dynamic Linq to add LIKE to where clause

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

Get all the includes from an Entity Framework Query?

I've the following Entity Model : Employee has a Company and a Company has Employees.
When using the Include statement like below:
var query = context.Employees.Include(e => e.Company);
query.Dump();
All related data is retrieved from the database correctly. (Using LEFT OUTER JOIN on Company table)
The problem is hat when I use the GroupBy() from System.Linq.Dynamic to group by Company.Name, the Employees are missing the Company data because the Include is lost.
Example:
var groupByQuery = query.GroupBy("new (Company.Name as CompanyName)", "it");
groupByQuery.Dump();
Is there a way to easily retrieve the applied Includes on the 'query' as a string collection, so that I can include them in the dynamic GroupBy like this:
var groupByQuery2 = query.GroupBy("new (Company, Company.Name as CompanyName)", "it");
groupByQuery2.Dump();
I thought about using the ToString() functionality to get the SQL Command like this:
string sql = query.ToString();
And then use RegEx to extract all LEFT OUTER JOINS, but probably there is a better solution ?
if you're creating the query in the first place - I'd always opt to save the includes (and add to them if you're making a composite query/filtering).
e.g. instead of returning just 'query' return new QueryContext {Query = query, Includes = ...}
I'd like to see a more elegant solution - but I think that's your best bet.
Otherwise you're looking at expression trees, visitors and all those nice things.
SQL parsing isn't that straight either - as queries are not always that simple (often a combo of things etc.).
e.g. there is a `span' inside the query object (if you traverse a bit) which seems to be holding the 'Includes' but it's not much help.

Translate odata uri to expression

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.

convert linq to object query to sql query (no linq to sql code or datacontext)

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.

DynamicObject LINQ query does't works with custom class!

DynamicObject LINQ query with the List compiles fine:
List<string> list = new List<string>();
var query = (from dynamic d in list where d.FirstName == "John" select d);
With our own custom class that we use for the "usual" LINQ compiler reports the error "An expression tree may not contain a dynamic
operation":
DBclass db = new DBclass();
var query = (from dynamic d in db where d.FirstName == "John" select d);
What shall we add to handle DynamicObject LINQ?
Does DBClass implement IEnumerable? Perhaps there is a method on it you should be calling to return an IEnumerable collection?
You could add a type, against which to write the query.
I believe your problem is, that in the first expression, where you are using the List<>, everything is done in memory using IEnumerable & Link-to-Objects.
Apparently, your DBClass is an IQueryable using Linq-to-SQL. IQueryables use an expression tree to build an SQL statement to send to the database.
In other words, despite looking much alike, the two statements are doing radically different things, one of which is allowed & one which isn't. (Much in the way var y = x * 5; will either succeed or fail depending on if x is an int or a string).
Further, your first example may compile, but as far as I can tell, it will fail when you run it. That's not a particular good benchmark for success.
The only way I see this working is if the query using dynamic is made on IEnumerables using Link-to-Objects. (Load the full table into a List, and then query on the list)

Resources