.NET Core从Oracle视图取数据时间歇性返回空白结果问题
.NET Core LINQ查询Oracle视图间歇性返回空结果
背景
我正在.NET Core应用程序中使用LINQ查询从Oracle视图获取数据。
问题
- 大多数时候数据能正常接收,但会间歇性返回空白结果。
- 示例:使用相同查询参数,有时能获取100行数据,有时却返回0行。
- 无错误抛出(调试器不会进入
catch块)。 - 重新执行几次LINQ查询后,数据恢复正常。
补充信息
- 同一应用中使用LINQ查询SQL Server(不同上下文)未出现类似问题。
- 使用
Microsoft.EntityFrameworkCore (2.1.4)。 - 不清楚Oracle版本,仅知晓视图名称及列信息。
代码配置
实体模型
[Table("ORACLE_VIEW", Schema = "APPS")] public class ORACLE_VIEW: BaseOracleEntity { public string ORDER_NUMBER { get; set; } public string ORDER_DESC { get; set; } public string STATUS { get; set; } ... }
public abstract class BaseOracleEntity { [Key] public int ID { get; set; } }
仓储层
public interface IEntityORACLE_VIEW : IGenericOracleRepository <ORACLE_VIEW> { }
public class EntityORACLE_VIEW: GenericOracleRepository <ORACLE_VIEW>, IEntityORACLE_VIEW { private AppDbOracleContext context; public EntityORACLE_VIEW(AppDbOracleContext _context) : base(_context) { this.context = _context; } }
public class GenericOracleRepository<T> : IGenericOracleRepository<T> where T : BaseOracleEntity { protected DbContext _entities; protected readonly DbSet<T> _dbset; public GenericOracleRepository(DbContext dbContext) { _entities = dbContext; _dbset = dbContext.Set<T>(); _entities.Database.ExecuteSqlCommandAsync("alter session set NLS_LANGUAGE = 'AMERICAN'"); } public virtual IQueryable<T> Table { get { return this._dbset; } } public virtual IQueryable<T> TableNoTracking { get { return this._dbset.AsNoTracking(); } } //... has Add, Delete, Edit and few more methods, but not used in LINQ query }
Startup配置
在ConfigureServices方法中:
services.AddDbContext<AppDbOracleContext>(options => options.UseOracle(Configuration.GetConnectionString("OracleConnString"))); ... ... services.AddScoped<IEntityORACLE_VIEW, EntityORACLE_VIEW>();
DbContext
public class AppDbOracleContext : DbContext { public AppDbOracleContext(DbContextOptions<AppDbOracleContext> options) : base(options) { } public DbSet<ORACLE_VIEW> ORACLE_VIEW{ get; set; } }
查询方法
public object GetOracleView(Model obj) { try { var res = (from orcUser in _entityORACLE_VIEW.TableNoTracking where (obj.WoStatus == null || !obj.WoStatus.Any() || obj.WoStatus.Contains(orcUser.STATUS)) && (string.IsNullOrWhiteSpace(obj.Search) || (!string.IsNullOrWhiteSpace(orcUser.ORDER_DESC) && orcUser.ORDER_DESC.ToUpper().Contains(obj.Search.ToUpper())) || (!string.IsNullOrWhiteSpace(orcUser.ORDER_NUMBER) && orcUser.ORDER_NUMBER.ToUpper().Contains(obj.Search.ToUpper())) ) select new ORACLE_VIEW_GridModel { Id = orcUser.ID, Order = orcUser.ORDER_NUMBER, Status = orcUser.STATUS, Description = orcUser.ORDER_DESC }) .OrderByDescending(ord => ord.ORDER_NUMBER) .ToList(); int count = res.Count(); var result = res.Skip(obj.Skip).Take(obj.Take).ToList(); return new APIResult { Result = result, Count = count }; } catch (Exception ex) { return new APIResult { ErrorDescription = ex.Message }; } }
排查与解决建议
1. 修复未等待的异步会话配置
仓储构造函数中调用ExecuteSqlCommandAsync但未等待完成,会导致会话语言设置可能还没生效就执行查询,引发字符集、大小写匹配异常:
// 改为同步执行,确保会话设置生效后再操作 _entities.Database.ExecuteSqlCommand("alter session set NLS_LANGUAGE = 'AMERICAN'");
若必须用异步,需重构仓储初始化逻辑,确保异步操作完成后再使用仓储实例。
2. 升级EF Core版本
你使用的Microsoft.EntityFrameworkCore 2.1.4版本较老,早期Oracle EF Core驱动存在连接池、查询生成的bug,建议升级到3.1.x或更高LTS版本,同时确保Oracle驱动版本与EF Core兼容。
3. 排查Oracle视图本身问题
- 导出LINQ生成的SQL,直接在Oracle客户端执行,看是否也会间歇性空结果,排除EF Core问题;
- 检查视图定义,确认是否依赖会话参数(如当前用户、NLS设置)的动态过滤逻辑;
- 确认Oracle用户对视图底层表的权限稳定,无临时回收情况。
4. 优化大小写匹配逻辑
查询中使用客户端ToUpper()可能因Oracle会话参数不稳定导致匹配异常,改用EF Core原生函数实现不区分大小写匹配:
// 替换原有的ToUpper().Contains逻辑 || EF.Functions.Like(orcUser.ORDER_DESC, $"%{obj.Search}%") || EF.Functions.Like(orcUser.ORDER_NUMBER, $"%{obj.Search}%")
同时确保Oracle会话的NLS_COMP设置为LINGUISTIC或BINARY_CI,保证匹配一致性。
5. 重置连接池会话状态
连接池复用的连接可能存在会话参数不一致问题,可在DbContext配置中强制设置会话选项:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseOracle(connectionString, o => o.SetSessionOptions(s => s.Set("NLS_LANGUAGE", "AMERICAN"))); }
内容的提问来源于stack exchange,提问作者Sampath
相关产品推荐
相关产品推荐

