Select не работает на IQueryable, но работает на IList - PullRequest
4 голосов
/ 05 июня 2011

У меня есть две строки кода, одна из которых

AllItems().Where(c => c.Id== id)
          .Select(d => new Quality(d.QualityType)).ToList();

, а другая

AllItems().Where(c => c.Id== id).ToList()
          .Select(d => new Quality(d.QualityType)).ToList();

Единственное отличие состоит во втором операторе ToList(), который вызывается после Where заявление.Второй параметр работает просто отлично.

В первом утверждении вместо конструктора с параметром используется конструктор без параметров по умолчанию.таким образом, список создается, но объекты в списке инициализируются значениями по умолчанию, а не d.QualityType.

Вы можете увидеть полный исходный файл, о котором идет речь, в (Метод: GetBestQualityInHistory)

https://github.com/kayone/NzbDrone/blob/master/NzbDrone.Core/Providers/HistoryProvider.cs

** Редактировать: После дальнейшего изучения, это, кажется, ошибка SubSonic, если Last ToList заменен на OrderBy дозвуковых бросков The construtor 'Void .ctor(NzbDrone.Core.Repository.Quality.QualityTypes, Boolean)' is not supported.

Ответы [ 2 ]

4 голосов
/ 05 июня 2011

Если SubSonic работает так же, как Entity Framework, вы не можете использовать конструкторы с параметрами - вы должны использовать конструкторы и инициализаторы без параметров.Мое объяснение очень высокого уровня состоит в том, что запрос не выполняется как есть - он переводится в SQL, и поэтому вы должны использовать инициализаторы свойств, чтобы дерево выражений знало, какие свойства в проецируемом типе должны заполняться значениями.При использовании конструктора с параметрами дерево выражений не знает, к чему принадлежит передаваемый параметр (оно не проверяет содержимое конструктора).Реальный конструктор (без параметров) вызывается после выполнения Tolist, а набор результатов материализуется в QuantityType экземпляров.

0 голосов
/ 06 июня 2011

На самом деле это не ответ, и я собирался сделать это комментарием, но мне нужно больше места для фрагмента кода.

Судя по коду SubSonic, яЯ уверен, что в некоторых случаях, когда вы получаете ошибки «конструктор не поддерживается», SS по какой-то причине пытается проанализировать ваш оператор new ...() в SQL.Оскорбительный метод является частью средства форматирования SQL и выглядит так, как будто он обрабатывает только DateTime:

    protected override NewExpression VisitNew(NewExpression nex)
    {
        if (nex.Constructor.DeclaringType == typeof(DateTime))
        {
            // ...omitted for brevity...
        }
        throw new NotSupportedException(string.Format("The construtor '{0}' is not supported", nex.Constructor));
    }

Я думаю, что это обычно срабатывает, если вы сделаете что-то вроде:

someData .Where (data => data.CreatedDate <= new DateTime (2011, 12, 01)). Выберите (data => data)

Тогда это newDateTime будет преобразовано в SQL.Поэтому, как бы вы ни изменили Linq, чтобы получить это исключение, я думаю, что это то, что происходит.Я предполагаю, что это потому, что если вы добавите .OrderBy() после .Select(), то вы больше не вызываете OrderBy для IQueryable того, что возвращает AllItems (), а вместо этого пытаетесь упорядочить по тому, что возвращается.Select (), который является множеством новых объектов качества, поэтому SS, вероятно, пытается превратить все это в SQL.

Интересно, будет ли это работать правильно, если вы изменили его?

AllItems().Where(c => c.Id== id)
      .OrderBy(d => d.QualityType)
      .Select(d => new Quality(d.QualityType));
...