LINQ: нет перевода на SQL - PullRequest
       11

LINQ: нет перевода на SQL

0 голосов
/ 05 июня 2009

Можете ли вы объяснить, почему пример # 1 не работает с "No Translation to SQL" и пример # 2 работает нормально?

Все в хранилище:

EX # 1:

public DomainPerson GetBestPerson()
{       
       var person= GetPeople().Where(p=>p.Quality=="Best").SingleOrDefault();
       return person;
}

public IQueryable<DomainPerson> GetPeople()
{
       var people= from p in Data.Persons
                   select MapToDomain(p);

       return people;
}

private DomainPerson MapToDomain(Data.Person dataPerson)
{   
       DomainPerson domainPerson= new DomainPerson{
                                  Id=dataPerson.Id,
                                  Name=dataPerson.Name,
                                  Quality=dataPerson.Quality,
                                  };
       return domainPerson;
}  

EX # 2

 public DomainPerson GetBestPerson()
{       
       var person= GetPeople().Where(p=>p.Quality=="Best").SingleOrDefault();
       return person;
}

public IQueryable<DomainPerson> GetPeople()
{
       var people= from p in Data.Persons
                   select new DomainPerson{
                   Id=dataPerson.Id,
                   Name=dataPerson.Name,
                   Quality=dataPerson.Quality,
                   };


       return people;
}

Ответы [ 4 ]

1 голос
/ 05 июня 2009

Как уже упоминалось, это связано с кодом, над которым работает LINQ To SQL.

Вы должны посмотреть на это немного так. В вашем первом примере - если мы посмотрим на выражения (то есть на дерево выражений), которые сгенерирует GetPeople, - человеческими словами он создаст дерево, которое указывает, что мы выбираем из нашей таблицы, - а затем применим функцию MapToDomain к каждой строке в этой таблице. который возвращает объект типа DomainPerson.

Во втором примере на этот раз мы не только знаем, что возвращаемый тип имеет DomainPerson, но мы также можем видеть, какие поля сопоставляются с какими свойствами (и, что еще более важно, как). Это означает, что когда вы в дальнейшем запустите свой Where и ссылку p.Quality, Linq To SQL может отследить это до таблицы SQL и будет знать, что DomainPerson.Quality отображается на столбец Quality в таблице Persons.

Поначалу может показаться странным, что первый пример не работает, но предположим, что ваша модель MapToDomain выглядит так:

public void DomainPerson MapToDomain(Data.Person person){
    return new DomainPerson {
        Quality = person.Quality + " Quality";
        //mode code here
    };
}

Теперь, как LINQ To SQL должен знать это "специальное" отображение? - ответ прост - не может.

Проще говоря, когда вы что-то делаете в своем операторе выбора и хотите проецировать свой результат, фактическое проецирование должно происходить как «встроенный» код (я не уверен в точном термине для этого), если после этого вы хотите больше выполнять запросы (т. е. упорядочивать, фильтровать и т. д.), иначе у движка запросов не будет ни единого шанса узнать, как работает ваше отображение.

1 голос
/ 05 июня 2009

Причина в том, что LINQ to SQL работает путем перевода деревьев выражений (Expression<Func<T>>) в SQL и запуска его на сервере. Метод, на который вы ссылаетесь в # 1, компилируется в IL. LINQ to SQL не может получить представление дерева выражений из своего тела.

Второй пример на самом деле не скомпилирован в IL. Он хранится в данных, которые могут быть прочитаны и переведены во время выполнения. Мой ответ на этот вопрос объясняет это подробно.

1 голос
/ 05 июня 2009

Во-первых, дерево выражений, созданное GetPeople (), содержит MapToDomain, который нельзя преобразовать в выражение SQL.

Рассмотрите возможность изменения MapToDomain, чтобы он возвращал IQueryable <> (*, и исправьте оставшиеся вызовы для MapToDomain (), чтобы они вызывали SingleOrDefault (). Проще сделать это, чем объяснить, я не скомпилировал это, поскольку у меня нет базового доступные объекты:

    public DomainPerson GetBestPerson()
    {       
           var person= GetPeople().Where(p=>p.Quality=="Best").SingleOrDefault();
           return person;
    }

    public IQueryable<DomainPerson> GetPeople()
    {
           return MapToDomain(Data.Persons);
    }

    IQueryable<DomainPerson> MapToDomain(IQueryable<Person> persons)
    {
        return persons.select(dataPerson => new DomainPerson{
                                      Id=dataPerson.Id,
                                      Name=dataPerson.Name,
                                      Quality=dataPerson.Quality,
                                      };
    }
0 голосов
/ 05 июня 2009

Неудобно, что конструктор DomainPerson может быть переведен, а метод MapToDomain не может быть.

Возможно, в этой истории есть нечто большее, чем показанный код. Во втором примере здесь есть синтаксическая ошибка:

выберите нового DomainPerson {

Это действительно анонимный тип в реальном коде?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...