You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 23:05:08