首页 > 解决方案 > 使用 LINQ 查询 ODataV4 连接的服务 - 从表中获取最后一条记录

问题描述

我试图从 C# 应用程序查询我的 OData web 服务。

当我执行以下操作时:

var SecurityDefs = from SD in nav.ICESecurityDefinition.Take(1) 
                   orderby SD.Entry_No descending 
                   select SD;

我得到一个例外,因为 .top() 和 .orderby 不应该一起使用。

我需要获取数据集中的最后一条记录,并且只有最后一条。

目的是获取分类帐中最后使用的条目号,然后继续创建新条目,增加找到的条目号。

我似乎无法在网上找到任何解释如何做到这一点的东西。

服务仅返回来自提要的最后一条记录非常重要,因为速度在此解决方案中至关重要。

标签: c#odatadynamics-navodata-v4

解决方案


我得到一个例外,因为 .top() 和 .orderby 不应该一起使用。

你在哪里读到的?一般情况下.top()or.Take()只能与WITH一起使用 .orderby(),否则不能保证检索到的记录是可重复的或可预测的。

可能这里的复合问题是混合查询流畅的表达式语法,这是有效的,但您必须了解优先顺序。您的语法采用 1 条记录,然后应用排序顺序...您可能会发现从这样的查询
开始更容易:

// build your query
var SecurityDefsQuery = from SD in nav.ICESecurityDefinition 
                        orderby SD.Entry_No descending 
                        select SD;
// Take the first item from the list, if it exists, will be a single record.
var SecurityDefs = SecurityDefsQuery.FirstOrDefault();
// Take an array of only the first record if it exists
var SecurityDefsDeferred = SecurityDefsQuery.Take(1); 

这可以使用括号在单行上执行,但是您可以看到两种情况下的查询是相同的,SecurityDefs在这种情况下是单个ICESecurityDefinition类型的记录,而 asSecurityDefsDeferredIQueryable<ICESecurityDefinition>只有单个记录的记录。

如果您只需要记录本身,那么您就是这一行:

var SecurityDefs = (from SD in nav.ICESecurityDefinition 
                    orderby SD.Entry_No descending 
                    select SD).FirstOrDefault();

您也可以使用流利的表示法执行相同的查询:

var SecurityDefs = nav.ICESecurityDefinition.OrderByDescending(sd => sd.Entry_No)
                                            .FirstOrDefault();

在这两种情况下,.Take(1)或者.top()都是通过 .top() 实现的.FirstOrDefault()。您已经指出速度很重要,所以使用.First()or.FirstOrDefault()代替.Single()or.SingleOrDefault()因为单个变体将实际请求.Take(2)并且如果返回 1 或没有结果将引发异常。

这两个查询的OrDefault变体不会影响查询本身的性能,并且对您的代码的影响应该可以忽略不计,请使用适合您使用返回记录的逻辑的变体,并且如果您需要在存在的情况下处理这种情况是没有现有记录。

如果返回的记录有很多列,并且您只对Entry_No列值感兴趣,那么也许您应该简单地查询该特定值本身:

查询表达式

var lastEntryNo = (from SD in nav.ICESecurityDefinition 
                   orderby SD.Entry_No descending 
                   select SD.Entry_No).FirstOrDefault();

流利的表达

var lastEntryNo = nav.ICESecurityDefinition.OrderByDescending(sd => sd.Entry_No)
                                           .Select(sd => sd.Entry_No)
                                           .FirstOrDefault();

如果速度是最重要的,那么考虑在服务上提供一个特定的自定义端点来提供记录或根本不处理客户端中的“Entry_No”,让代码的工作从客户端接收数据并计算它在插入条目时。

使查询执行得更快并不是您可能正在寻找的灵丹妙药,即使这是高度优化的,您当前的模式也意味着X客户端数量都可以调用服务以获取当前值Entry_No,这意味着所有客户端都将启动从相同的值递增。

如果您必须Entry_No客户端增加,那么您应该考虑在服务上放置一个自定义端点,以便简单地返回Next Entry_No以供使用。这应该是乐观的,这意味着您不关心最终是否Entry_No实际使用,但您可以实现端点,以便每次调用都会增加数据库中的字段并返回下一个值。

它有点超出了您最初帖子的范围,但是 SQL Server 现在支持从数据库和模式的角度形式化这种类型的逻辑的序列,使用序列简化了我们如何从客户端管理这些类型的增量,因为我们不再依赖于在客户端增加下一条记录之前将数据更新的结果提交到表中。(这就是您的TOP,Order By Desc解决方案正在尝试做的事情。


推荐阅读