EF Core结合Oracle使用Skip和Take报错ORA-00933求助
问题场景
使用Oracle.EntityFrameworkCore NuGet包时,编写带Skip和Take的LINQ查询:
var q = db.Set<T>() .FilterBy(filtri) .Skip(0) .Take(10);
生成的SQL被包装在PL/SQL块中,触发**ORA-00933(SQL命令未正确结束)**错误:
DECLARE l_sql varchar2(32767); l_cur pls_integer; l_execute pls_integer; BEGIN l_cur := dbms_sql.open_cursor; l_sql := 'SELECT "w"."REQUESTNUM", ..." FROM "MP2"."WOREQ" "w" WHERE (("w"."SITEID" = ''TESTCC'') AND ("w"."TASKNUM" = ''AAAQ'')) OFFSET :p_0 ROWS FETCH NEXT :p_1 ROWS ONLY'; dbms_sql.parse(l_cur, l_sql, dbms_sql.native); dbms_sql.bind_variable(l_cur, ':p_0', 0); dbms_sql.bind_variable(l_cur, ':p_1', 10); l_execute:= dbms_sql.execute(l_cur); dbms_sql.return_result(l_cur); END;
去掉Skip和Take后,生成的普通SQL可正常执行:
SELECT "w"."REQUESTNUM", ... FROM "MP2"."WOREQ" "w" WHERE (("w"."SITEID" = 'TESTCC') AND ("w"."TASKNUM" = ''AAAQ''))
原因分析
从生成的PL/SQL代码能看到,l_sql变量的字符串存在语法错误:SELECT行末尾多了一个未闭合的双引号(..."),导致整个SQL语句格式不完整,触发ORA-00933错误。这是Oracle EF Core驱动在生成带分页的PL/SQL包装代码时的潜在bug。
解决方法
升级Oracle.EntityFrameworkCore版本
该问题大概率是驱动版本的已知bug,建议升级到最新稳定版。Oracle官方后续版本修复了不少SQL生成的语法问题,升级后分页语句的PL/SQL包装逻辑会修正这个引号错误。禁用PL/SQL包装生成
如果暂时无法升级,可以通过配置禁用EF Core对查询的PL/SQL包装,让驱动直接生成纯SQL语句而非PL/SQL块。在DbContext的OnConfiguring方法中添加配置:protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseOracle("your_connection_string", o => o.UseOracleSQLCompatibility("12") // 确保使用Oracle 12c+的分页语法 .DisablePLSQLWrapping()); // 禁用PL/SQL包装 }注意:
UseOracleSQLCompatibility("12")是因为OFFSET/FETCH语法从Oracle 12c开始支持,需确保你的数据库版本≥12c。替换Skip(0)为条件判断
如果Skip的参数是0,可以通过代码逻辑跳过Skip调用,因为Skip(0)不会改变查询结果,反而可能触发驱动的错误分支:var query = db.Set<T>().FilterBy(filtri); if (skipCount > 0) { query = query.Skip(skipCount); } query = query.Take(10);这种方式避免了生成带Skip(0)的分页语句,绕过了驱动的bug场景。
内容的提问来源于stack exchange,提问作者Max Bertoli

