选择不上IQueryable的工作,但确实在IList的

问题描述:

我有两行代码,一个是选择不上IQueryable的工作,但确实在IList的

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

**编辑:经过进一步调查,这似乎是一个亚音速的bug,如果最后ToList被替换为OrderBy亚音速抛出The construtor 'Void .ctor(NzbDrone.Core.Repository.Quality.QualityTypes, Boolean)' is not supported

+0

你在这里调用了'ToList' * both * cases,但是在第二种情况下,你调用它*两次*。为什么? – 2011-06-05 19:28:25

+0

对不起,这只是错误复制过去 – 2011-06-05 19:29:02

+0

AllItems是什么类型?它只是一个内存列表,或者它是通过例如持久性框架提供给您的东西吗? 可能是相关的,因为如果不使用ToList,持久性框架将处理呼叫。据我所知.net在tolist后处理它(因为它是一个列表之后) – thekip 2011-06-05 19:31:44

如果SubSonic以与Entity框架相同的方式工作,您不能使用带参数的构造函数 - 您必须使用无参数的构造函数和初始化函数。我非常高层次的解释是,查询没有按原样执行 - 它被转换为SQL,因此您必须使用属性初始值设定项,以便表达式树知道投影类型中的哪些属性应该由值填充。当使用带参数的构造函数时,表达式树不知道传入的参数属于哪里(它不检查构造函数的内容)。一旦执行Tolist并将结果集实现为QuantityType实例,就会调用真正的构造函数(无参数)。

+0

代码最初使用了初始化器,我将其更改为构造函数以追踪问题。 – 2011-06-05 19:54:39

+0

神圣的包装。我刚刚在EF 3.5中测试了参数化构造函数的用法,并且我希望你错了......但是,你是对的。我感到眼花缭乱。 EF会抛出一个“LINQ to Entities支持只有无参数的构造函数和初始化器”。例外。 EF 4.0中仍然如此?我一直在用LINQ to SQL来做这件事。 – Steven 2011-06-05 20:08:23

+0

@Steven:是的,它在EFv4中是一样的,根据这一点,它应该在Linq-to-sql中也是一样的,但我没有自己尝试。 – 2011-06-05 20:28:05

这不是一个真正的答案,我打算将它作为评论,但需要更多的代码片段空间。

通过SubSonic代码判断,我敢肯定,在某些情况下,如果您得到“构造函数不支持”的错误,SS出于某种原因试图将您的new ...()语句解析为SQL。该问题的方法是SQL格式化的一部分,看起来像它只能处理日期时间:

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 。哪里(数据=> data.CreatedDate < = new DateTime(2011,12,01)) .Select(data => data)

然后,newDateTime将被转换为SQL。 所以,不管你如何改变Linq来获得这个异常,我认为这就是发生了什么。 我认为这是因为如果您在.Select()之后添加.OrderBy()那么您不再调用AllItems()返回的IQueryable上的OrderBy,而是尝试按.Select()返回的内容排序,这是新的质量对象的枚举,所以SS可能会试图将所有这些转换为SQL。

我想知道如果它能正常工作,如果你扭转它?

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