EF Core 无法直接调用 Oracle 自定义集合函数,须用原生 SQL + SqlQuery 配合 TABLE() 包装调用,T 为无键 DTO;参数需用 OracleParameter 绑定,字段名须与 Oracle 返回列名完全一致(大小写敏感),且数据库自定义类型须与 DTO 严格匹配。

EF Core 本身不支持直接调用 Oracle 自定义函数(尤其是返回自定义集合类型如 UT_BLOCKED_STATISTICS_LIST)并自动映射为实体列表。必须绕过 EF Core 的 LINQ 查询管道,用原生 SQL + SqlQuery<t></t> 配合 TABLE() 函数包装调用,且 T 必须是无键 DTO。
Oracle 自定义函数需用 TABLE() 包装才能被当作表查询
Oracle 的自定义函数若返回集合类型(如 UT_BLOCKED_STATISTICS_LIST),不能像存储过程那样用 PL/SQL 块调用;必须用 SQL 层的 SELECT * FROM TABLE(函数名(...)) 语法,让 Oracle 将其“展开”为结果集。
-
TABLE()是 Oracle 特有语法,EF Core 不识别它作为函数调用,只能当普通 SQL 字符串传入 - 函数参数必须用命名占位符(如
:begintime),不能用位置参数或字符串拼接(防注入) - 日期参数要显式转成
DATE类型,例如TO_DATE(:begintime, 'yyyy-mm-dd hh24:mi:ss') - 最终 SQL 示例:
"SELECT * FROM TABLE(get_BLOCKED_STATISTICS(TO_DATE(:begintime, 'yyyy-mm-dd hh24:mi:ss'), TO_DATE(:endtime, 'yyyy-mm-dd hh24:mi:ss')))"
SqlQuery<t></t> 要求 T 是无主键、无导航属性的纯 DTO
EF Core 7+ 的 SqlQuery<t></t> 不走实体跟踪,也不校验主键——但如果你的 T 类里有 [Key] 或继承了带主键的基类,运行时可能报错或结果为空。
- DTO 类字段名必须和函数返回的列名**完全一致(大小写敏感)**,因为 Oracle 默认大写,而 .NET 属性默认 PascalCase;建议统一用大写字段名或加
[Column("TWO_DPT_CDE")] - 在
OnModelCreating中必须配置:modelBuilder.Entity<blockedstatistics>().HasNoKey();</blockedstatistics> - 不要在该类上加
[Table]或任何关系配置,否则 EF 可能尝试做额外元数据解析
参数传递必须用 OracleParameter,不能用内插字符串
Oracle 驱动(Oracle.ManagedDataAccess.Core)对参数绑定较严格:字符串插值会直接拼进 SQL,导致日期格式错误、引号逃逸失败、SQL 注入风险。
- 所有参数必须是
OracleParameter实例,类型(OracleDbType)要匹配函数定义(如Varchar2、Date、Int32) - 日期参数推荐用
DateTime类型传入,驱动会自动处理时区和精度;避免传字符串再靠TO_DATE转换(易出错) - 示例代码片段:
var beginParam = new OracleParameter("begintime", OracleDbType.Date) { Value = DateTime.Now.AddDays(-7) };
var endParam = new OracleParameter("endtime", OracleDbType.Date) { Value = DateTime.Now };
var results = context.Database.SqlQuery<BlockedStatistics>(
"SELECT * FROM TABLE(get_BLOCKED_STATISTICS(:begintime, :endtime))",
beginParam, endParam
).ToList();多结果集或嵌套对象无法自动展开
如果自定义函数返回的是嵌套结构(比如一个字段是 JSON 字符串或另一个自定义对象),EF Core 的 SqlQuery<t></t> 只做扁平映射——它不会递归解析 JSON,也不会把字段映射成子对象。
- 遇到
VARCHAR2存 JSON 的情况,只能先映射为string,再用System.Text.Json手动反序列化 - 若函数返回多个不同结构的集合(比如同时返回统计摘要 + 明细列表),EF Core 一次
SqlQuery只能取一个结果集;需拆成多次调用或改用DbCommand手动读取多个OracleRefCursor - 注意:
TABLE()只适用于返回集合类型的函数,不适用于返回单个标量(如NUMBER或VARCHAR2)的函数;后者应改用ExecuteSqlRaw+ 输出参数
最易被忽略的一点:Oracle 自定义类型(OBJECT / TABLE OF OBJECT)必须在数据库中已存在,且 .NET 端 DTO 的字段顺序、名称、类型必须与数据库类型定义逐字匹配——差一个空格或大小写都可能导致 ORA-00902: invalid datatype 或静默空结果。


















