1

I'm extend a SELECT function in order to select custom fields of SELECT from list of string.

The function you will see in images bellow is: SelectExtend() at line 201.

When i'm running in debug mode. The query value in Watch window are difference when i run over line 201.

I have captured the image about before and after calling the SelectExtend() function.

Anyone can explain to me why the query return "System.Data.Entity.Infrastructure.DbQuery", not "Select [Project1].[ID], ...."?

I want the query return as "Select [Project1].[ID], ...."

Thanks for reading.

Before run over line 201

After run over line 201

And here are source code of function "SelectExtend()"

public static IQueryable<T> SelectExtend<T>(this IQueryable<T> source, List<string> fields)
    {
        if (fields == null || fields.Count <= 0)
            throw new ArgumentException("'fields' can not be null or empty.");

        var parameter = Expression.Parameter(source.ElementType, "x");
        var body = Expression.MemberInit(
            Expression.New(typeof(T)),
            fields.Select(field => Expression.Bind(
                typeof(T).GetProperty(field),
                Expression.PropertyOrField(parameter, field))
            )
        );

        var selector = Expression.Lambda(body, parameter);
        var expression = Expression.Call(
            typeof(Queryable)
            , "Select"
            , new[] { source.ElementType, selector.Body.Type }
            , source.Expression
            , Expression.Quote(selector)
        );

        return source.Provider.CreateQuery<T>(expression);
    }
Minh Nguyễn
  • 63
  • 1
  • 1
  • 8
  • Because it's an internal representation that will only produce SQL after the SQL Translator is run on it. You will need to either [set the DbContext.Database.Log property](https://stackoverflow.com/questions/16880687/how-can-i-log-the-generated-sql-from-dbcontext-savechanges-in-my-program/20757916#20757916) or implement an interceptor. For an example see [EF6.x Correlating Poor Performing SQL to Application Code](https://romiller.com/2016/02/11/ef6-x-correlating-poor-performing-sql-to-application-code/) – Andrés Robinet Aug 03 '17 at 04:42
  • Also, consider [LinqKit](https://github.com/scottksmith95/LINQKit) and [NeinLinq](https://github.com/axelheer/nein-linq) for dynamically building LINQ expressions. And, I'd rather create a DTO instead of retrieving an incomplete entity. Check [Automapper](https://github.com/AutoMapper/AutoMapper.EF6) – Andrés Robinet Aug 03 '17 at 04:51
  • Most likely it's indication that the query cannot be translated to SQL and will generate runtime exception due to projection to entity type. – Ivan Stoev Aug 03 '17 at 08:27
  • Does the queryable work anyway? – tinudu Aug 03 '17 at 09:09

1 Answers1

0

Not exactly sure what's going on. Usually it's the Queryable.XXX methods that call the provider, passing it an expression of a call to themselves. They might do it somehow differently though.

What if you modify your method such that you call .Select and return what it returns (cleaner code as a bonus)?

Note that in your case typeof(T), source.ElementType and selector.Body.Type are all the same.

public static IQueryable<T> SelectExtend<T>(this IQueryable<T> source, IList<string> fields)
{
    if (source == null) throw new ArgumentNullException(nameof(source));
    if (fields == null) throw new ArgumentNullException(nameof(fields));

    var parameter = Expression.Parameter(typeof(T), "x");
    var body = Expression.MemberInit(
        Expression.New(typeof(T)),
        fields.Select(field => Expression.Bind(
            typeof(T).GetProperty(field),
            Expression.PropertyOrField(parameter, field))
        )
    );
    var selector = Expression.Lambda<Func<T, T>>(body, parameter);
    return source.Select(selector);
}

(Also removed the check for zero fields, since your code can still do what it's supposed to.)

If you still get the same result, then everything might be OK. After all, what you see in the debugger is just what a class decides to display, by default the result of .ToString().

tinudu
  • 1,139
  • 1
  • 10
  • 20