Why is it the syntax of the Select property in the LinqDataSource so different from Linq I would write inline in C#? I mean like:
new (Id As MyId, Name As MyName)
vs
new (MyId = Id, MyName = Name)
And the syntax diverges more when you start doing things like concatenation in the projection. I am using this with a Entity Data model as the provider, if that has anything to do with it.
I would have expected something called a LinqDataSource would simply allow you to supply a compiled Linq query and be done with it.
Also I could find no documentation on the syntax of what is expected for the Select property other than the most simple cases of aliasing the fields. The Linq Concat command doesn't work, and it was only a stroke of luck that I found a blog where someone figured out an alternative. So in the future when trying to do any other manipulations I pretty much can only take wild guesses in the dark.
I think it is because the as keyword has already a different meaning in the language. The chosen syntax resembles the syntax of default parameters (.net 4.0 following) and is pretty clear IMHO.
Note that this explicit syntax is only necessary when a property name for an anonymous type cannot be inferred or is ambigous.
Related
We are investigating using LinQ to query an internal dynamic collection created by Dapper. The question is:
How to execute dynamic LinQ against the collection using Scott Guthrie dynamic linq (or some other technology if possible)? (http://weblogs.asp.net/scottgu/dynamic-linq-part-1-using-the-linq-dynamic-query-library)
This is what we want to do (much simplified):
Use Dapper to return a dynamic collection (here called rows):
rows = conn.Query(“select ACCOUNT, UNIT, AMOUNT from myTable”);
If we use a “static” LinQ query there is no problem. So this works fine:
var result = rows.Where(w => w.AMOUNT > 0);
But we would like to write something similar to this using dynamic Linq:
var result = rows.Where("AMOUNT > 0");
But we can’t get this to work.
The error we get is:
No property or field ‘AMOUNT’ exists in type ‘Object’
(We have tried a lot of other syntax also – but cant get it to work)
Please note: We do not want to use dynamic SQL when Dapper requests data from the database (that is easy). We want to execute many small dynamic Linq statements on the collection that the Dapper query returns.
Can it be that ScottGu dynamic Linq only works with ‘LinQ to SQL’?
Is there some other alternative approach to achieve the same thing?
(Performance is a key issue)
/Erik
conn.Query("...")
returns an IEnumerable<dynamic>. However, "dynamic LINQ" pre-dates dynamic, and presumably nobody has updated it to work with dynamic; it could certainly be done, but it is work (and isn't trivial). Options:
use Query<T> for some T
make the required changes to "dynamic LINQ", and preferably make those changes available to the wider community
I suspect that conn.Query(“select ACCOUNT, UNIT, AMOUNT from myTable”); returns IEnumerable<object>. In order for DLinq to work, you need to have IEnumerable<TheActualType>.
You can try this:
conn.Query<dynamic>("yourQueryString")
.ToList()
//.ToAnonymousList()
.Where("AMOUNT > 0");
If that doesn't work, you could try and use ToAnonymousList, that tries to return the IList<TheActualType.
I'm using Dynamic LINQ with NHibernate.
Simple example demonstrates my problem:
var q = sess.Query<User>().Select("new (Id, Login, Person.Id as PersonId)");
throws NullReferenceException when where are Users in database with User.Person == null.
This solves the problem:
var q = sess.Query<User>().Select(new { Id, Login, PersonId = (long?)Person.Id });
but I need something like
var q = sess.Query<User>().Select("new (Id, Login, (long?)Person.Id as PersonId)");
because select expression is generated dynamically.
Unfortunately dynamic LINQ does not understand cast to (long?) :(
What should I have to do?
Thanks in advance!
==== Edit ====
Ok, I understood two things:
1. Dynamic LINQ does not know about long, only Int64.
2. Cast is not '(Int64)something' but 'Int64(something)'.
So whole my code should be
sess.Query<User>().Select("new (Id, Login, Int64?(Person.Id) as PersonId)");
But it still does not solve my whole problem because NHibernate now fails with Could not execute query[SQL: SQL not available] exception and NullReference inner exception.
Finally I have mastered the problem. I studied Dynamic.cs and found that the Dynamic LINQ's syntax is very specific. Particularly the string expression "SomeType(SomeExpression)" generates cast expression only if SomeType has no constructor with one parameter. In other case it generates "new SomeType(SomeExpression)". I considered it as a mistake and slightly modified the Dynamic.cs.
Now in my example the cast can be made as 'Int64? Person.Id'. It is not a "normal" cast syntax but it works for me like a charm. Dynamic ExpressionParser is pretty good but unfortunately is not well adapted for C# cast syntax.
Also I registered in Dynamic.cs short type names like "long", "int" etc.
The modified source is downloadable here: http://1drv.ms/1cRJtSP .
I have the following lines of code in C#
that gets data using DataTables
This is pretty generic and helps me with multiple tables.
object obj = ((DataRowView)editingElement.DataContext).Row[this.SelectedValuePath];
I want to change this statement to a generic LINQ statement so that i can use it with multiple LINQ tables too.
Can somebody help me figure this out?
I don't think you can use LINQ to make the code you wrote nicer or more elegant in any way. I assume that the type of editingElement.DataContext is object, so you'll need to write the cast anyway. If you forget about the casting, your code is just indexed access:
var rows = (DataRowView)editingElement.DataContext;
object obj = rows.Row[this.SelectedValuePath];
LINQ doesn't have any features that would make indexing nicer, so I think this is the best you can get. One possible ugly thing is that you get object as the result and you'll need to cast that to some other type (e.g. CustomerInfo).
If you were using LINQ from the beginning (to populate the data for the DataContext), you could probably write something like this to access the customer:
var rows = (IEnumerable<CustomerInfo>)editingElement.DataContext;
CustomerInfo info = rows.Row[this.SelectedValuePath];
This would be a bit more elegant, because you'd need just a single cast. However, I think that your code is fine and LINQ cannot help you (in this piece of code).
My Lucene queries will usually exist of a bunch of AND combined fields.
Is it possible to get the queried fields out of the Query object again?
Did you mean extracting the terms or the field names? Since you already know you're handling a BooleanQuery, to extract the fields you can simply iterate the BooleanClause array returned by BooleanQuery.getClauses(), rewrite each clause to its base query (Query.rewrite) and apply recursively until you have a TermQuery on your hands.
If you did mean term extraction, I'm not sure about Lucene.NET, but in Java Lucene you can use org.apache.lucene.search.highlight.QueryTermExtractor; you pass a (rewritten) query to one of its getTerms overloads and get an array of WeightedTerms.
As far as I remember, the downsides to using this technique are:
Since it internally uses a term set it won't handle multiple instances of the same token, e.g. "dream within a dream"
It only supports base query types (TermQuery, BooleanQuery and any other query type which supports Query.extractTerms). I believe we've used it internally for SpanNearQuery and SpanNearOrderedQuery instances, but I may be wrong on this.
Either way I hope this is enough to get you started.
What would be the best approach to allow users to define a WHERE-like constraints on objects which are defined like this:
Collection<object[]> data
Collection<string> columnNames
where object[] is a single row.
I was thinking about dynamically creating a strong-typed wrapper and just using Dynamic LINQ but maybe there is a simpler solution?
DataSet's are not really an option since the collections are rather huge (40,000+ records) and I don't want to create DataTable and populate it every time I run a query.
What kind of queries do you need to run? If it's just equality, that's relatively easy:
public static IEnumerable<object[]> WhereEqual(
this IEnumerable<object[]> source,
Collection<string> columnNames,
string column,
object value)
{
int columnIndex = columnNames.IndexOf(column);
if (columnIndex == -1)
{
throw new ArgumentException();
}
return source.Where(row => Object.Equals(row[columnIndex], value);
}
If you need something more complicated, please give us an example of what you'd like to be able to write.
If I get your point : you'd like to support users writting the where clause externally - I mean users are real users and not developers so you seek solution for the uicontrol, code where condition bridge. I just though this because you mentioned dlinq.
So if I'm correct what you want to do is really :
give the user the ability to use column names
give the ability to describe a bool function (which will serve as where criteria)
compose the query dynamically and run
For this task let me propose : Rules from the System.Workflow.Activities.Rules namespace. For rules there're several designers available not to mention the ones shipped with Visual Studio (for the web that's another question, but there're several ones for that too).I'd start with Rules without workflow then examine examples from msdn. It's a very flexible and customizable engine.
One other thing: LINQ has connection to this problem as a function returning IQueryable can defer query execution, you can previously define a query and in another part of the code one can extend the returned queryable based on the user's condition (which then can be sticked with extension methods).
When just using object, LINQ isn't really going to help you very much... is it worth the pain? And Dynamic LINQ is certainly overkill. What is the expected way of using this? I can think of a few ways of adding basic Where operations.... but I'm not sure how helpful it would be.
How about embedding something like IronPython in your project? We use that to allow users to define their own expressions (filters and otherwise) inside a sandbox.
I'm thinking about something like this:
((col1 = "abc") or (col2 = "xyz")) and (col3 = "123")
Ultimately it would be nice to have support for LIKE operator with % wildcard.
Thank you all guys - I've finally found it. It's called NQuery and it's available from CodePlex. In its documentation there is even an example which contains a binding to my very structure - list of column names + list of object[]. Plus fully functional SQL query engine.
Just perfect.