I've found an error in the LINQ translator (4.3 RC2)

A query like this :

var result = Query.All<MyEntity>().Select(e => new Dictionary<string, object>() { { "Text", e.Text }, {"Date", e.Date} }).ToList();

Gives this exception:

Xtensive.Storage.Linq.TranslationException was unhandled
  Message=Unable to translate 'Query.All().Select(e => new Dictionary<String,Object>() {
  {"Text", e.Text}
})' expression. See inner exception for details.
       at Xtensive.Storage.Linq.QueryProvider.Translate[TResult](Expression expression)
       at Xtensive.Storage.Linq.QueryProvider.Execute[TResult](Expression expression)
       at Xtensive.Storage.Linq.Queryable`1.GetEnumerator()
  InnerException: System.InvalidCastException
       Message=Unable to cast object of type 'Xtensive.Storage.Linq.ConstructorExpression' to type 'System.Linq.Expressions.NewExpression'.
            at Xtensive.Core.Linq.ExpressionVisitor.VisitListInit(ListInitExpression li)
            at Xtensive.Core.Linq.ExpressionVisitor`1.Visit(Expression e)
            at Xtensive.Storage.Linq.Translator.Visit(Expression e)
            at Xtensive.Storage.Linq.Translator.VisitLambda(LambdaExpression le)
            at Xtensive.Storage.Linq.Translator.BuildProjection(LambdaExpression le)
            at Xtensive.Storage.Linq.Translator.VisitSelect(Expression expression, LambdaExpression le)
            at Xtensive.Storage.Linq.Translator.VisitQueryableMethod(MethodCallExpression mc, QueryableMethodKind methodKind)
            at Xtensive.Core.Linq.QueryableVisitor.VisitMethodCall(MethodCallExpression mc)
            at Xtensive.Storage.Linq.Translator.VisitMethodCall(MethodCallExpression mc)
            at Xtensive.Core.Linq.ExpressionVisitor`1.Visit(Expression e)
            at Xtensive.Storage.Linq.Translator.Visit(Expression e)
            at Xtensive.Storage.Linq.Translator.Translate[TResult]()
            at Xtensive.Storage.Linq.QueryProvider.Translate[TResult](Expression expression)

Test project: [attachment=0:1t73gmpu]TestDynamicSelect.zip[/attachment:1t73gmpu]

Query selecting to a dictionary are useful for dynamic select.

Could you investigate this behavior?

Regards, Julien

Updated at 07.06.2010 12:44:33

Well, actually this is really what I want : the columns in this query would be chosen dynamically be user.

So I want a list of objects to show in a GUI with a dynamic field choice. So I tried to use Dictionary<string, object=""> to represent a dynamic object, but I want to replace this with an ExpandoObject. However this query fails with DO (but this works with LinqToObjects)

Updated at 08.06.2010 8:43:31

To Alex: Well the goal of this is to find a way to dynamically specify columns to fetch via a GUI : I want to be able to choose the columns to fetch in SQL. So using L2E to make the final projection is not really what I need, because in that case I will be fetching all the columns from the database, and then discarding the data.

I think you should fix it, but I've found a workaround going like this :

class MyDictionary<TKey, TValue> : Dictionary<TKey, TValue>
    public MyDictionary(TKey[] keys, TValue[] values)
      for (int i = 0; i < keys.Length; i++)
        this.Add(keys[i], values[i]);

Query.All<MyEntity>().Select(e => new MyDictionary<string, object>( new string[] { "Text", "Date"}, new object[] { e.Text, e.Date }))

The workaround is less elegant, but works : so it's not really important to fix it ASAP.

To psulek: This is very interesting : I will investigate to see if we will use the new C#4 dynamics. I wonder about the performance... But using dynamics could allow dynamic and flexible code.

Thanks for the idea!

This thread was imported from our support forum. The original discussion may contain more detailed answer.

asked Jun 07 '10 at 07:45

olorin's gravatar image


One Answer:

You create dictionary for each entry in MyEntity, but finally convert this dictionary (precisely Queryable<dictionary<string, object="">>) to generic List (by calling ToList() at the end). You can rewrite your select this way:

var result = Query.All<MyEntity>().ToDictionary(key => key.Text, value => value.Date);

here ToDictionary is what you need to use.

Than you can use this construct (only in .NET 4 because there is used dynamic keyword):

var result = Query.All<MyEntity>().Select(e => new dynamic[]
                   new {Key = "Text", Value = e.Text},
                   new {Key = "Date", Value = e.Date}

Here, i am using anonymous class with properties Key and Value,

new {Key = "Text", Value = e.Text}

and then returns array of dynamic objects (e => new dynamic[]), where are boxed that anonymous class into array.

Then you can iterate result like this:

foreach (var item in result)
    dynamic[] dictionary = item;
    foreach (dynamic dict in dictionary)
        string key = dict.Key;
        object value = dict.Value;

...where each item in result is dynamic array of objects (dynamic[]). Keyword dynamic, is important here because later we can obtain values from properties Key and Value, which will not be possible with earlier .net framework where we can use only object[].

See attached zip file which contains Program.cs.

To psulek: This is very interesting : I will investigate to see if we will use the new C#4 dynamics. I wonder about the performance... But using dynamics could allow dynamic and flexible code. Thanks for the idea! You're welcome :-)

answered Jun 07 '10 at 08:39

Peter%20%C5%A0ulek's gravatar image

Peter Ĺ ulek

We'll try to fix this, although I'm not sure if this is realyl important - i.e. if you're talking about final projection, normally it's possible to implement this using L2E (LINQ to Enumerable).

So what do you think, does it worth to implement this ASAP?

(Jun 07 '10 at 08:39) Alex Yakunin Alex%20Yakunin's gravatar image
Your answer
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!
toggle preview

powered by OSQA