首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >我能控制Oracle如何映射ADO.NET中的整数类型吗?

我能控制Oracle如何映射ADO.NET中的整数类型吗?
EN

Stack Overflow用户
提问于 2015-09-16 17:16:44
回答 2查看 533关注 0票数 0

我有一个遗留数据库,它是用数据库类型INTEGER for many (1.000+) Oracle列创建的。MS SQL存在具有相同结构的数据库。据我所知,最初的定义是使用一个工具创建的,该工具为MS SQL和Oracle生成从逻辑模型到特定模型的脚本。

使用C++和MFC,列可以很好地映射到两个数据库管理系统的整数类型。

我正在将这个应用程序移植到.NET和C#。使用相同的C#代码库来访问MS和Oracle。我们使用相同的DataSets和逻辑,我们需要相同的类型(两者都使用int32)。

Oracle的ODP.NET驱动程序将它们映射到Decimal。这是合乎逻辑的,因为Oracle自动将整数列创建为NUMBER(37)。MS SQL中的列映射到int32。

我能以某种方式控制如何映射ODP.NET驱动程序中的类型吗?我想说一些类似"map NUMBER(37) to int32“的话。列中的值永远不会超过int32的限制。我们之所以知道这一点,是因为它正在MS SQL版本中使用。

或者,我是否可以将所有列从NUMBER(37)修改为NUMBER(8)或SIMPLE_INTEGER,以便它们为我们映射到正确的类型?这些列中的许多列被用作主键(考虑自动增量)。

EN

回答 2

Stack Overflow用户

发布于 2015-09-22 20:56:00

关于类型映射,希望这就是你所需要的

http://docs.oracle.com/cd/E51173_01/win.122/e17732/entityDataTypeMapping.htm#ODPNT8300

关于类型转换,如果表为空,可以使用如下脚本(只需将YOUR_TABLE_NAME替换为大写的表名即可):

代码语言:javascript
复制
DECLARE
  v_table_name CONSTANT VARCHAR2(30) := '[YOUR_TABLE_NAME]';
BEGIN
  FOR col IN (SELECT * FROM user_tab_columns WHERE table_name = v_table_name AND data_type = 'NUMBER' AND data_length = 37)
  LOOP
    EXECUTE IMMEDIATE 'ALTER TABLE '||v_table_name||' MODIFY '||col.column_name||' NUMBER(8)';
  END LOOP;
END;

如果其中一些列不为空,则不能降低它们的精度

如果您没有太多数据,可以将其移动到临时表中

代码语言:javascript
复制
create table temp_table as select * from [YOUR_TABLE_NAME]

然后截断原始表

代码语言:javascript
复制
truncate [YOUR_TABLE_NAME]

然后运行上面的脚本

然后将数据移回

代码语言:javascript
复制
insert /*+ append */ into [YOUR_TABLE_NAME] select * from temp_table
commit

如果数据量很大,最好移动一次。在这种情况下,使用正确的数据类型和所有索引、约束等创建新表,然后移动数据,然后重命名这两个表,以使新表具有正确的名称,这样会更快。

票数 1
EN

Stack Overflow用户

发布于 2015-09-23 02:42:53

不幸的是,.NET和Oracle之间的数值类型映射是在OracleDataReader类中硬编码的。

通常,我更喜欢在数据库中设置适当的数据类型,因此如果可能,我会更改列数据类型,因为它们更好地表示实际值,并且它们的constraints.

  • Another选项是使用强制转换为(8)的视图来包装表,但这将对执行计划产生负面影响,因为它禁止索引查找。

然后,您还有一些应用程序实现选项:

  1. 实现您自己的数据读取器或Oracle类的子集(继承自DbProviderFactory、DbConnection、DbCommmand、DbDataReader等并包装Oracle类),具体取决于您的实现有多复杂。Oracle.DataAccess、Devart和所有的提供者都做了完全相同的事情,因为它提供了对一切的完全控制,包括数据类型的任何魔法。如果数据类型转换是您唯一想要实现的事情,那么大多数实现将只是在命令执行之后调用您可以访问OracleDataReader的包装类methods/properties.
  2. If,并且在开始读取它之前,您可以做一个简单的修改并使用反射来设置结果数字类型(下面的实现就是简化的demonstration).

但是,这不适用于ExecuteScalar,因为此方法永远不会公开底层数据读取器。

代码语言:javascript
复制
var connection = new OracleConnection("DATA SOURCE=HQ_PDB_TCP;PASSWORD=oracle;USER ID=HUSQVIK");
connection.Open();

var command = connection.CreateCommand();
command.CommandText = "SELECT 1 FROM DUAL";

var reader = command.ExecuteDatabaseReader();
reader.Read();
Console.WriteLine(reader[0].GetType().FullName);
Console.WriteLine(reader.GetFieldType(0).FullName);

public static class DataReaderExtensions
{
    private static readonly FieldInfo NumericAccessorField = typeof(OracleDataReader).GetField("m_dotNetNumericAccessor", BindingFlags.NonPublic | BindingFlags.Instance);
    private static readonly object Int32DotNetNumericAccessor = Enum.Parse(typeof(OracleDataReader).Assembly.GetType("Oracle.DataAccess.Client.DotNetNumericAccessor"), "GetInt32");
    private static readonly FieldInfo MetadataField = typeof(OracleDataReader).GetField("m_metaData", BindingFlags.NonPublic | BindingFlags.Instance);
    private static readonly FieldInfo FieldTypesField = typeof(OracleDataReader).Assembly.GetType("Oracle.DataAccess.Client.MetaData").GetField("m_fieldTypes", BindingFlags.NonPublic | BindingFlags.Instance);

    public static OracleDataReader ExecuteDatabaseReader(this OracleCommand command)
    {
        var reader = command.ExecuteReader();
        var columnNumericAccessors = (IList)NumericAccessorField.GetValue(reader);
        columnNumericAccessors[0] = Int32DotNetNumericAccessor;

        var metadata = MetadataField.GetValue(reader);
        var fieldTypes = (Type[])FieldTypesField.GetValue(metadata);
        fieldTypes[0] = typeof(Int32);

        return reader;
    }
}

我实现了命令执行的扩展方法,返回读取器,我可以在其中设置所需的列数字类型。不设置数字访问器(它只是内部枚举Oracle.DataAccess.Client.DotNetNumericAccessor),您将获得System.Decimal,设置了访问器,您将获得Int32。使用它,你可以得到所有的Int16,Int32,Int64,Float或Double。VARCHAR是一个列索引,它将只应用于数字类型,如果columnNumericAccessors是DATE或VARCHAR列,则忽略数字访问器。如果您的实现没有公开特定于提供程序的类型,请在IDbCommand或DbCommand上创建扩展方法,然后将DbDataReader安全地强制转换为OracleDataReader。

编辑:为GetFieldType方法添加了hack。但可能会发生静态映射哈希表可能会被更新,因此这可能会产生不必要的影响。您需要正确地测试它。fieldTypes数组保存为数据读取器的所有列返回的类型。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32604384

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档