Select 在 IQueryable 上不起作用,但在 IList 上起作用

发布于 2024-11-13 15:04:33 字数 946 浏览 2 评论 0原文

我有两行代码,一行

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 错误,如果最后一个 ToList 被替换为 OrderBy 亚音速抛出一个 The construtor 'Void .ctor(NzbDrone.Core.Repository.Quality.QualityTypes, Boolean)' is not支持。

I have two lines of code, one is

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

and the other one

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

The only difference is on the second statement ToList() is called after the Where statement. The second statment works just fine.

On the first statement, the default parameterless constructor is hit instead of the constructor with the parameter. so the list is created but the objects in the list are initialized with default values rather than with the d.QualityType.

you can see the full source of the file in question at (Method: GetBestQualityInHistory)

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

**Edit: After further investigation, this seems to be a SubSonic bug, if the Last ToList is replaced by an OrderBy subsonic throws an The construtor 'Void .ctor(NzbDrone.Core.Repository.Quality.QualityTypes, Boolean)' is not supported.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

渔村楼浪 2024-11-20 15:04:33

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

If SubSonic works in the same way as Entity framework you cannot use constructors with parameters - you must use parameterless constructors and initializers. My very high level explanation of this is that the query is not executed as is - it is translated to SQL and because of that you must use property initializers so that expression tree knows which properties in the projected type should be filled by values. When using constructor with parameters, expression tree doesn't know where the passed parameter belongs to (it doesn't check content of the constructor). The real constructor (parameterless) is called once you execute Tolist and result set is materialized into QuantityType instances.

无语# 2024-11-20 15:04:33

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

从 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
.Where(data => data.CreatedDate <= new DateTime(2011, 12, 01))
.Select(data => data)

然后 newDateTime 将被转换为 SQL。
因此,无论您如何更改 Linq 来获得该异常,我认为这就是正在发生的情况。
我认为这是因为如果您在 .Select() 之后添加 .OrderBy() 那么您将不再调用 OrderBy IQueryable 可以查询 AllItems() 返回的内容,但会尝试按 .Select() 返回的内容进行排序,这是新质量对象的可枚举,因此 SS 可能会尝试将所有这些转换为 SQL。

我想知道如果你反转它是否会正常工作?

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

This isn't really an answer, and I was going to make it a comment, but needed more room for code snippet.

Judging by the SubSonic code, I'm pretty sure that in some cases where you get the "constructor not supported" errors, SS is for some reason trying to parse your new ...() statement into SQL. The offending method is part of the SQL Formatter, and looks like it only handles 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));
    }

I think that would normally be hit if you did something like:

someData
.Where(data => data.CreatedDate <= new DateTime(2011, 12, 01))
.Select(data => data)

Then that newDateTime would be translated to SQL.
So however you change the Linq to get that exception, I think that is what is happening.
I assume this is because if you add an .OrderBy() after the .Select() then you are no longer calling the OrderBy on the IQueryable of whatever AllItems() returns, but instead trying to order by what is returned by the .Select(), which is the enumerable of new Quality obejcts, so SS probably tries to turn all that into SQL.

I'm wondering if it would work right if you reversed it?

AllItems().Where(c => c.Id== id)
      .OrderBy(d => d.QualityType)
      .Select(d => new Quality(d.QualityType));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文