【问题标题】:Malfunction linq - the newest entry in the database故障 linq - 数据库中的最新条目
【发布时间】:2014-10-14 19:33:00
【问题描述】:
decimal tmpPreviousSellingRate = db.DataServiceCurrenciesRates
                                   .Where(x => x.CurrencyId == tmpCurrencyId)
                                   .OrderByDescending(x => x.PublicationDate)
                                   .Select(x => x.SellingRate)
                                   .DefaultIfEmpty()
                                   .First();

在数据库中我有:

CurrencyId: 1 PublicationDate: '2014-08-19' SellingRate: 3,4530
CurrencyId: 2 PublicationDate: '2014-08-19' SellingRate: 0,6117
CurrencyId: 3 PublicationDate: '2014-08-19' SellingRate: 1,3570

CurrencyId: 1 PublicationDate: '2014-08-20' SellingRate: 3,3753
CurrencyId: 2 PublicationDate: '2014-08-20' SellingRate: 0,5442
CurrencyId: 3 PublicationDate: '2014-08-20' SellingRate: 1,5478

CurrencyId: 1 PublicationDate: '2014-08-21' SellingRate: 3,38263
CurrencyId: 2 PublicationDate: '2014-08-21' SellingRate: 0,5837
CurrencyId: 3 PublicationDate: '2014-08-21' SellingRate: 1,4635

当 CurrentId 为 2 时,我想得到 0,5837,但在 tmpPreviousSellingRate 中是 0,6117(从 2014-08-19 开始)

我使用了 OrderByDescending 和 OrderBy - 结果是一样的,都是 0,6117。

使用 .Last() 而不是 .First() 我得到一个错误

"Additional information: LINQ to Entities does not recognize the method 'System.Decimal Last[Decimal](System.Linq.IQueryable`1[System.Decimal])' method, and this method cannot be translated into a store expression."

【问题讨论】:

  • PublicationDate 列的数据类型是什么?
  • 您是否检查了 Where 子句是否返回了与 CurrencyId == 2 相关的三个条目?尝试删除 DefaultIfEmpty() 和 First(),您应该检索有序列表。
  • PublicationDatedate。不,我没有检查我现在就做。
  • 是的,在Where 中都是三个条目。
  • Last()can't be mapped to a Sql query。如果Where 谓词之后的数据量很小,您可以在应用链的其余部分之前使用.ToList() 实现数据。此外,您应该能够用单个 FirstOrDefault() 替换最后两个函数

标签: c# linq entity-framework linq-to-entities


【解决方案1】:

我试图复制您的问题,但我设法从这段代码中得到了预期的结果:

public class DBData
{
    public int CurrencyId { get; set; }
    public DateTime PublicationDate { get; set; }
    public decimal SellingRate { get; set; }
}

public class Program
{
    private static void Main(string[] args)
    {
        var items = new List<DBData>();

        items.Add(new DBData { CurrencyId = 1, PublicationDate = DateTime.Parse("2014-08-19"), SellingRate = 34530m });
        items.Add(new DBData { CurrencyId = 2, PublicationDate = DateTime.Parse("2014-08-19"), SellingRate = 6117m });
        items.Add(new DBData { CurrencyId = 3, PublicationDate = DateTime.Parse("2014-08-19"), SellingRate = 13570m });
        items.Add(new DBData { CurrencyId = 1, PublicationDate = DateTime.Parse("2014-08-21"), SellingRate = 338263m });

        decimal result = items
            .Where(x => x.CurrencyId == 1)
            .OrderByDescending(x => x.PublicationDate)
            .Select(x => x.SellingRate)
            .FirstOrDefault();
    }
}

我看到的结果是338263m,我相信这与您预期的结果相似。

不是一个真正的答案,但我暂时将这段代码留在这里,以防它被证明有用。如果没有,我将删除我的答案进行清理。

编辑:

我将 LINQ 代码更改为使用 FirstOrDefault(),因为这是获取项目实例或默认(即引用类型为 NULL)对象的更一致的方法,而不是分别调用 DefaultIfEmpty()First()

【讨论】:

  • 我认为对数据库运行 LINQ 生成的查询是不同的。事实上DefaultIfEmpty()First() 通常会混淆结果。
  • @FrancescoDeLisi 已更新答案以反映您的评论。
  • @JasonEvans 请看我的回答。您的原始问题包含与问题中失败的代码完全相同的代码。现在您已将其更改为可行的方法,但没有任何解释。
【解决方案2】:

这很奇怪,但是文字的变化

.DefaultIfEmpty()
.First();

到这里

.FirstOrDefault();

工作。

【讨论】:

  • Doh,我在我的代码中错过了这一点。但是,是的,使用FirstOrDefault() 更有意义。
  • 请看我的回答。
【解决方案3】:

您必须非常小心OrderBy 之后调用的方法,因为它们会使它失去顺序。这与查询的延迟执行有关:在 LINQ to EF 中,LINQ 查询只有在必要时才会转换为 SQL,即直到您将其具体化。

当您调用OrderBy 时,它会返回一个IOrderedQueryable&lt;T&gt;,其中包含有关排序的信息。此时,您可以做三件不同的事情:

  1. 使用ToListFirst 等任何方法实现查询。这样做时,订购信息可用并被使用
  2. 调用IOrederedQueryable 的任何方法(或扩展方法)返回一个新的IOrderedQueryable。当您这样做时,订购信息仍然存在。例如,您可以调用ThenBy,它将添加订购信息并返回一个新的IOrderedQueryable。当您具体化此查询时,如 1 中所述,将使用订购信息
  3. 最后,您可以调用任何其他丢失订购信息的扩展方法。这是可能的,因为IOrderedQueryable 也是IQueryable。因此,您可以调用任何获得IOrderedQueryable 的扩展方法,但返回一个简单的IQueryable。如果您这样做,订购信息会丢失,并且当您实现查询时(如 1 中所示),订单也会丢失。

为避免此问题,您应该在最后一刻执行OrderBy,以保证在查询具体化之前保留排序信息。

在您的情况下,DefaultIfEmpty 扩展方法返回一个IQueryable,因此当您使用First 实现它时,订购信息不可用。

但是,当您使用FirstOrDefault 时,您将实现IOrderedQueryable,这使它起作用。 IE。调用此方法时,SQL 查询已创建,并且订购信息仍然可用。

当您使用 Linq to Objects 时,它以不同的方式工作。它使用IOrderedEnumerable,这是一种完全不同的动物。因此,您不能保证所有适用于 LINQ to Objects 的功能也适用于 LINQ to EF。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-06
    • 2010-10-12
    • 1970-01-01
    • 2012-02-26
    • 1970-01-01
    相关资源
    最近更新 更多