EKsumic's Blog

let today = new Beginning();

Click the left button to use the catalog.

OR

SqlException:关键字'SELECT'附近有语法错误。“)”附近有语法错误。“OFFSET”附近有语法错误。在FETCH语句中选项NEXT的用法无效

浏览器报错页面:

SqlException: 关键字 'SELECT' 附近有语法错误。 “)”附近有语法错误。 “OFFSET”附近有语法错误。 在 FETCH 语句中选项 NEXT 的用法无效。

错误位置:

                   var TopArticles = BlogsModel.Where(x => x.IsTop == true);                        
                    BlogsModel = BlogsModel.Except(TopArticles).OrderByDescending(x => x.PublishTime);
                    BlogsModel=TopArticles.Concat(BlogsModel).Skip(SkipCount).Take(pageSize);
                }               
            }
            return View(await BlogsModel.ToListAsync());
        }
        public async Task<IActionResult> Category(string id,int pageNum=1)
        {
            int AuthorId = 1;

这是一个来自.NET Core 2.1 迁移到3.1之后发生的错误,开始我是以为是数据库问题,升级了数据库之后,依旧报错。于是我选择了卸载所有数据库并重新安装SQL Server 2017 Express版本,然后报错依旧……

我认为代码是没有错误的,因为它在.NET Core 2.1正常运行了。(也就是我现在正在用的博客项目)

我加过断点调试,只有当return的一瞬间会跑到WEB页面报错,原因应该是前台Razor页面获取不到BlogsModel,于是我尝试直接传递BlogsModel给前台,最终在foreach语句停下,仍然报的是一样的错误……

我怀疑是数据库没装好,于是尝试直接在数据库里面用FETCH NEXT语句执行查询,发现执行成功!暂时排除了数据库问题。

那么问题应该出在ORM上面了,EntityFramework在把我的语句翻译成SQL的时候发生了致命的错误,这个问题应该不在我身上。

因为不是特别懂FETCH NEXT语句,所以姑且认为是ORM的问题,或者直接说是.NET Core 3.1 的问题,因为3.1废除了UseRowNumberForPaging()这个方法,同时还严格限制GroupBy语句的使用,使我不得不在GroupBy之前增加AsEnumerable()。

3.1相对2.1有很大的性能提升,如果说是通过严格限制LINQ语句来达成的话,那我觉得我还不如直接写SQL吧。

 

对于该错误,我还存在疑惑:

  • 我是否真的安装成功了SQL Server?
  • 是否真的是3.1的EntityframeworkCore的问题,BUG?
  • 是否因为早期版本的原因,Visual Studio 2019 Community默认还是以2008 R2的引擎在驱动?

sql 2017 install

第一个困惑 来源于全文和语义提取搜索,因为没有用过,并且也搜索不到是否与FETCH NEXT有关,猜测可能是因为没装这个功能所引起的。(但后来发现,这个功能根本装不上去,所以就想到去拿阿里云的云服务器去试,最后发现阿里云有两层防火墙,根本进不来1433端口,所以就此罢休)

在自己的开发环境,2008R2和2017的实例共存的情况下,在2017里建立存储过程中用到了FETCH NEXT发现可以执行,所以姑且先排除了全文和语义提取搜索这个可能。我觉得根本原因还是EntityFrameworkCore没有把我的LINQ语句正确转换成SQL,这是直接原因。

间接原因我想有2点:

  1. 错误的迁移方式,后台并不认为前台是Razor
  2. .NET Core 3.1 固有Bug

我倾向于第2点,因为第一点我已经重新写过一个3.1项目,试过了依然报错。

.NET Core 3.1 是LTS版本,意味着会去维护和修复,这个版本还很不完整,所以这种BUG可能存在,而且还是只有我碰到了,因为我的代码逻辑不倾向于性能。逻辑上实现了,但是可能多次重复查询字段,最好的方式当然是读1次数据库然后开始处理,我大概为了去对比某些字段而读取了好几次……但这些都不是重点,关键是.NET Core 3.1限制了GroupBy的使用,这意味着我可能要用两个Where去替代它,要产生更多的代码量。

而.NET Core 3.1可能不仅仅限制了GroupBy,也许还限制了List传递到前台的可能性。

像ToListAsync()这样的方法,在我的前台页面是行不通的。

但是,新的疑惑出现了,return View(await BlogsModel.ToListAsync());是我照着HomeController等基架原生出来的代码写的,而用基架生成的页面没有任何错误,我写的页面却报错了…… 难道我们用的不是同一个EntityFrameworkCore吗?

.NET Core Life Time

暂时没有解决方案,等 .NET 5.0 。

This article was last edited at 2020-06-22 17:40:53

* *