Управляемый ODP.Net - параметр в SELECT, приводящий к столбцам ReadOnly - PullRequest
0 голосов
/ 12 сентября 2018

Я спросил следующее на форуме Oracle Community , но SO, как правило, быстрее отвечает!


Я обнаружил проблему с Managed ODP.Net v18.3.0где наличие параметра Oracle в операторе SELECT приведет к тому, что DataTable будет иметь множество столбцов, помеченных как ReadOnly.При выполнении того же оператора SELECT без использования параметра Oracle эти столбцы не будут установлены как ReadOnly.

Вот пример консольного приложения C # (.Net 4.7.1), которое демонстрирует проблему:

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;

using Oracle.ManagedDataAccess.Client;

namespace ODP.NetParamsConsole
{
    class SimpleScenario
    {
        internal static void ExecuteScenario()
        {
            DataSet ds1 = new DataSet();
            string sqlNoParams = "SELECT F.FORMULA_CODE, nvl(null, 'Hard Coded Substitute Value') AS TEST_COLUMN, F.DESCRIPTION, F.YIELD, F.UOM_CODE FROM FSFORMULA F";
            GetData(sqlNoParams, ds1, "TABLENOPARAMS", null);

            string sqlWithParams = "SELECT F.FORMULA_CODE, nvl(null, :pSUBSTITUTE_VALUE) AS TEST_COLUMN, F.DESCRIPTION, F.YIELD, F.UOM_CODE FROM FSFORMULA F";

            List<OracleParameter> selectParams = new List<OracleParameter>()
            {
                NewParameter("SUBSTITUTE_VALUE", "Parameter Substitute Value")
            };
            GetData(sqlWithParams, ds1, "TABLEWITHPARAMS", selectParams);

            // This should return 0 different columns, but it will find that some of the columns are set to ReadOnly in the Param-based table.
            List<string> diffResults = TableCompare(ds1, "TABLENOPARAMS", "TABLEWITHPARAMS");
            Program.DisplayResults("Simple Scenario", diffResults);
        }

        private static void GetData(string SQL, DataSet DataSetToPopulate, string NewTableName, List<OracleParameter> OracleParameters)
        {
            using (OracleConnection conn = new OracleConnection("<my_connection_string>"))
            {
                conn.Open();
                using (OracleCommand cmd = conn.CreateCommand())
                {
                    if (OracleParameters?.Count > 0)
                    {
                        foreach (OracleParameter p in OracleParameters)
                            cmd.Parameters.Add(p);
                    }
                    cmd.CommandText = SQL;
                    using (OracleDataAdapter oracleDataAdapter = new OracleDataAdapter(cmd))
                    {
                        oracleDataAdapter.MissingSchemaAction = MissingSchemaAction.AddWithKey;
                        oracleDataAdapter.Fill(DataSetToPopulate, NewTableName);
                    }
                }

            }
        }

        private static OracleParameter NewParameter(string Name, object value)
        {
            OracleParameter p = new OracleParameter();
            p.ParameterName = "p" + Name;
            if (value != null)
                p.Value = value;
            return p;
        }

        private static List<string> TableCompare(DataSet dataSet, string table1, string table2)
        {
            List<string> diffColumns = new List<string>();
            foreach (DataColumn dc1 in dataSet.Tables[table1].Columns)
            {
                if (dc1.ReadOnly != dataSet.Tables[table2].Columns[dc1.ColumnName].ReadOnly)
                    diffColumns.Add(dc1.ColumnName);
            }
            return diffColumns;
        }

        private static void DisplayResults(string TestName, List<string> DifferentColumns)
        {
            Console.WriteLine(string.Format("Scenario: {1} - There are {0:N0} different columns between the two tables.", DifferentColumns.Count, TestName));
            foreach (string diffColumnName in DifferentColumns.OrderBy(dc => dc))
                Console.WriteLine("Column: " + diffColumnName);
        }
    }
}

Как вы можете видеть выше, операторы SELECT используют NVL функция (может быть любой функцией), и один из аргументов предоставляется либо путем жесткого кодирования значения в строку, либо путем передачи объекта параметра Oracle.Затем для заполнения набора данных результатами используется метод ODP.Net DataAdapter.Fill.Если вы используете опцию MissingSchemaAction.AddWithKey, то столбцы в таблице, заполненной SELECT с параметром, будут установлены на ReadOnly.Сравните это с таблицей, в которой не было параметра, и ни один из столбцов не установлен на ReadOnly.

Я обнаружил, что вы можете использовать параметр в другом месте в операторе SELECT (например, в предложении WHERE), и эта проблема ReadOnly отсутствует.Я также обнаружил, что вы должны использовать функцию с параметром в операторе SELECT, чтобы вызвать проблему.Использование параметра самостоятельно в списке выбранных столбцов также не представляет проблемы.И, как упоминалось ранее, вы должны выбрать опцию MissingSchemaAction.AddWithKey.

1 Ответ

0 голосов
/ 02 мая 2019

Oracle исправил это в версии управляемой сборки ODP.Net версии 18.6.0 (Oracle Bug 29242017).

...