【问题标题】:ODP.NET: Oracle.ManagedDataAccess.Client.OracleException (0x80004005): ORA-01841 on .NET 5 (Core) applicationODP.NET:Oracle.ManagedDataAccess.Client.OracleException (0x80004005):.NET 5(核心)应用程序上的 ORA-01841
【发布时间】:2021-06-02 08:18:03
【问题描述】:

尝试使用 Oracle.ManagedDataAcces.Client (ODP.NET) 和 C# .NET 5 Web 应用程序执行选择。

截至 2021 年 2 月 6 日,Oracle.ManagedDataAcces.Client 版本是最新的 3.21.1。

错误:

Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware1 执行请求时发生未处理的异常。 Oracle.ManagedDataAccess.Client.OracleException (0x80004005): ORA-01841: (full) year 必须在 -4713 和 +9999 之间,而不是 0 在 OracleInternal.ServiceObjects.OracleConnectionImpl.VerifyExecution(Int32& cursorId, Boolean bThrowArrayBindRelatedErrors, SqlStatementType sqlStatementType, Int32 arrayBindCount, OracleException& exceptionForArrayBindDML, Boolean& hasMoreRowsInDB, Boolean bFirstIterationDone)

这是查询代码

   public async Task<int> GetMyCount(string userName, int THE_YEAR)
    {
        try
        {
            string TEST = "STACK_OVERFLOW_TEST";
            builder.Clear();

            builder.Append($@" SELECT COUNT(*) 
                FROM {configuration.SCHEMA}.SOME_TABLE CA 
                INNER JOIN {configuration.SCHEMA}.SOME_OTHER_TABLE CS 
                ON CS.ID=CA.ID ");

            if (viewNotAll)
            {
                builder.Append($" INNER JOIN {unitOfWork.oracleDbOptions.DBSchemaQP}.ANOTHER_TABLE UT ON CA.SOME_FIELD = UT.SOME_FIELD ");
            }

            builder.Append(@$" WHERE CA.DATE_TO_FILET BETWEEN TO_DATE(CONCAT('0101', :THE_YEAR),'DDMMYYYY') 
            AND TO_DATE(CONCAT('3112', :THE_YEAR),'DDMMYYYY') ");


            if (TEST == "NO")
                builder.Append(" AND CS.TEST_FIELD=0 ");
            else
                builder.Append(" AND CS.TEST_FIELD=:THE_TEST_FIELD ");


            int result = 0;

            using (var cmd = unitOfWork.connection.CreateCommand())
            {

                cmd.Parameters.Add("THE_YEAR", OracleDbType.Int16, 4, THE_YEAR, ParameterDirection.Input);
                cmd.Parameters.Add("THE_TEST_FIELD", OracleDbType.Varchar2, 20, userName, ParameterDirection.Input);

                cmd.CommandText = builder.ToString();
                using (var reader = await cmd.ExecuteReaderAsync())
                {
                    while (await reader.ReadAsync())
                    {
                        result = reader.IsDBNull(0) ? 0 : reader.GetInt32(0);
                    }
                }

                return result;
            }
        }
        catch (Exception)
        {
            throw;
        }
    }

在 Oracle SQL Developer 或 PL/SQL 中执行查询是可行的。也来自visual studio server exporer 作品。弹出一个窗口询问参数,键入为 VARCHAR2,它执行查询正常。

我什么都试过了。出于测试目的,从 Int16、Int32、VARCHAR2 更改类型,也基于Oracle .NET type guide,其中指出 Int16 是长度为 4 的数字,在我的情况下是一年。 什么都没有。

我还尝试使用in this stackoverflow question 显示的内容来检索 SQL 查询历史记录,以发现显然从外部触发的查询不会被记录。我无法通过此查询找到它们。

它的唯一工作方式是直接连接查询中的值:

builder.Append(@$" WHERE CA.SOME_DATE BETWEEN TO_DATE(CONCAT('0101', '{THE_YEAR}'),'DDMMYYYY') 
            AND TO_DATE(CONCAT('3112', '{THE_YEAR}'),'DDMMYYYY') ");

但我想使用参数来避免 SQL 注入。

我做错了什么?

【问题讨论】:

    标签: c# oracle .net-5 odp.net oracle.manageddataaccess


    【解决方案1】:

    更好的使用

    builder.Append(@$" WHERE CA.DATE_TO_FILET BETWEEN :aDate AND :bDate");
    
    cmd.Parameters.Add("aDate", OracleDbType.Date, ParameterDirection.Input).Value = new DateTime(THE_YEAR, 1, 1);
    cmd.Parameters.Add("bDate", OracleDbType.Date, ParameterDirection.Input).Value = new DateTime(THE_YEAR, 12, 31);
    
                
    

    【讨论】:

    • 所以不是真正的解决方案,而是整个参数替换?
    • 您为什么不认为这是“真正的解决方案”?在字符串上使用TO_DATE() 对我来说看起来很愚蠢。直接使用DATE 值。
    【解决方案2】:

    CONCAT 连接两个字符串,因此 THE_YEAR 应该是一个由四个字符组成的字符串,而不是一个整数。你试过了吗

    cmd.Parameters.Add("THE_YEAR", OracleDbType.Varchar2, 4, THE_YEAR.ToString(), ParameterDirection.Input);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-16
      • 1970-01-01
      • 2016-11-12
      • 1970-01-01
      • 1970-01-01
      • 2018-05-14
      相关资源
      最近更新 更多