c# - 托管 ODP.Net - SELECT 中的参数导致只读列
问题描述
我也在Oracle 社区论坛上问过以下问题,但 SO 通常会更快回复!
我发现 Managed ODP.Net v18.3.0 存在问题,SELECT
语句中包含 Oracle 参数将导致DataTable
许多列标记为ReadOnly
. 在不使用 Oracle 参数的情况下执行相同的SELECT
语句,这些列将不会设置为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 Parameter 对象来提供参数之一。然后使用ODP.NetDataAdapter.Fill
方法用结果填充数据集。如果您使用该选项,则表中由具有参数MissingSchemaAction.AddWithKey
的 填充的列将设置为。将其与没有参数的表进行比较,并且没有任何列设置为.SELECT
ReadOnly
ReadOnly
我发现您可以在SELECT
语句的其他地方(如WHERE
子句)使用 Parameter ,并且ReadOnly
不存在此问题。我还发现您必须在语句中使用带有参数的函数SELECT
才能导致问题。在所选列的列表中单独使用参数也不会出现问题。如前所述,您也必须MissingSchemaAction.AddWithKey
选择该选项。
解决方案
Oracle 使用托管 ODP.Net 程序集的 18.6.0 版本修复了此问题(Oracle 错误 29242017)。
推荐阅读
- javascript - Javascript 速度改进
- javascript - 谷歌可视化多条形图
- yarnpkg - 为什么在 windows 上运行 yarn 会改变 yarn.lock
- php - Cookie 在 PHP 中的过期日期之前被删除
- electron - 电子。正在渲染一个空白屏幕
- python - 从列表中读取行时的for循环
- bash - 向zabbix发送数据时cron作业不起作用
- php - 浏览器返回后 Textarea 未重置
- python - Pandas 与重复键合并 - 删除重复行或阻止其创建
- selenium - 如何选择 XPath 不固定且有标签的动态 HTML 表的复选框?