LINQ:没有转换为SQL

时间:2009-06-04 21:42:16

标签: linq-to-sql

你能解释一下为什么示例#1因“No Translation to SQL”失败而示例#2工作正常吗?

All in Repository:

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 个答案:

答案 0 :(得分:1)

在第一个中,GetPeople()生成的表达式树包含MapToDomain,它无法转换为SQL表达式。

考虑更改MapToDomain,以便返回IQueryable&lt;&gt; (*并修复对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,
                                      };
    }

答案 1 :(得分:1)

原因是LINQ to SQL的工作原理是将表达式树Expression<Func<T>>)转换为SQL并在服务器上运行它。您在#1中引用的方法将编译为IL。 LINQ to SQL无法从其正文中获取表达式树表示。

第二个例子并没有真正编译成IL。它存储在可以在运行时读取和转换的数据中。 My answer for this question详细解释了这一点。

答案 2 :(得分:1)

正如其他人所提到的,它与LINQ To SQL的代码有关。

你必须看一下这个。在你的第一个例子中 - 如果我们看一下GetPeople将生成的表达式(即表达式树) - 用人类的话说它会生成一个树,指定我们从表中选择 - 然后在该表的每一行上应用MapToDomain函数碰巧返回DomainPerson类型的对象。

在第二个例子中,这次我们不仅知道返回类型是DomainPerson - 而且我们还能够看到哪些字段被映射到哪些属性(更重要的是如何)。这意味着,当您稍后运行Where和reference p.Quality时,Linq To SQL可以将其回溯到SQL表,并且知道DomainPerson.Quality映射到Persons表中的Quality列。

首先看起来有点奇怪,为什么第一个例子不起作用 - 但假设您的MapToDomain模型如此:

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

现在LINQ To SQL应该如何知道这种“特殊”映射? - anwer很简单 - 它不能。

简而言之 - 当您在select语句中执行任何操作并且想要投影结果时,实际投影需要全部作为“内联”代码发生(我不确定其中的确切术语)您希望在此之后再进行查询(即排序,过滤等) - 否则查询引擎无法知道您的映射是如何工作的。

答案 3 :(得分:0)

反直觉可以翻译DomainPerson构造函数,而不能使用MapToDomain方法。

或许故事的内容多于显示的代码。这里的第二个例子中存在语法错误:

选择新的DomainPerson {

这实际上是代码中的匿名类型吗?