如何从 ActiveRecord 访问隐藏列(在 Informix 中)

Posted

技术标签:

【中文标题】如何从 ActiveRecord 访问隐藏列(在 Informix 中)【英文标题】:How do I access hidden columns from ActiveRecord (in Informix) 【发布时间】:2010-01-24 04:18:33 【问题描述】:

许多数据库都有隐藏的主键列。 mysql 将其实现为 _rowid。在 MySQL 的情况下,它实际上是一个指向先前定义的主键列的指针。然而,在其他数据库中(在我的例子中是 Informix),此列独立于故意定义的主键。我编写的数据库主要是根据 Informix 隐藏列 ROWID 而不是定义主键的做法设计的。我正在使用 Informix JDBC 驱动程序从 JRuby on Rails 连接到 Informix。一切都很好,除了我想不出一种方法让隐藏的 rowid 列显示为 ActiveRecord 属性。所有其他字段都在那里,只是没有 rowid。如果我使用 What.find_by_sql("SELECT rowid,* FROMwhattable") 查询模型,它会返回一个“Whatever”对象数组,但 rowid 列不存在。

我研究过调整 JDBC 驱动程序、ActiveRecord 或数据库;什么都没有结果。

任何指导将不胜感激。

【问题讨论】:

【参考方案1】:

首先,请注意,如果您的表是碎片化的,则它不会有 ROWID - 除非您使用 WITH ROWIDS 子句创建它,在这种情况下,ROWID 将成为索引物理列而不是虚拟列。

其次,为什么不直接使用表的声明主键而不是在幕后钻研——尤其是在幕后钻研版本不起作用时。

我不清楚为什么您使用的显式符号没有按照您的要求执行;那可能是 JDBC 驱动程序在它的鼻子不属于的地方戳它的鼻子。您在结果集中返回了多少列?如果不是您选择的数字(表格中的列数加一),那么有些东西很可疑。

如果我需要查看 JDBC 驱动程序发送到服务器的内容,我将启用 SQLI 调试跟踪 - 在客户端或者,如果客户端不合作,在服务器端。在普通(基于 C 的)API 中,启用 SQLI 调试只需设置一个环境变量:

SQLIDEBUG=2:sqli

这将在运行 C API(ESQL/C、ODBC 等)的进程的当前目录中创建一个名称以“sqli_”开头的文件。我假设相同的机制应该适用于 JDBC 驱动程序。

如果 SQLIDEBUG 不能与 JDBC 一起工作,那么你的工作就更难了——你需要在服务器端启用 SQLI 调试。

假设您捕获 SQLI(SQL 接口)输出,然后您可以使用“sqliprint”打印它。您将查找发送到 IDS 的 SQL。如果它不包含 ROWID,那么您可以相当肯定 JDBC 驱动程序正在与您玩愚蠢的游戏。但是,目前尚不清楚您将采取什么措施来解决这个问题。也许尝试一个表别名(例如't')和:

SELECT t.ROWID, t.* FROM WhateverTable t WHERE ...

如果事实证明 JDBC 正在调整 ROWID,我们也可以尝试为它设置别名:

SELECT ROWID AS pk_column, t.* FROM WhateverTable AS t WHERE ...

(表名后面的AS是可选的。)

如果您发现任何有趣或有用的信息,请随时通知我们。


数据库已经安装在多个位置,并且已经编译了应用程序(源不可用),如果数据库架构发生更改,这些应用程序会中断,因此我无法添加合法的主键。这些应用程序依赖 rowid 作为主键。

好的;这是一个设计决策,应该在您的下一次主要升级时进行审查如果您的任何客户拥有足够大的数据量,碎片化可能是有益的。请记住,碎片表没有虚拟 ROWID 列;您可以通过在 CREATE TABLE 或 ALTER FRAGMENT 语句中使用 WITH ROWIDS 子句来使用物理 ROWID 列创建它们。

使用 log4jdbc 我能够确认发送到 Informix 的查询确实包含对 rowid 的请求。该值被返回并且 JDBC 驱动程序转换 ResultSet 中的每一列;我可以看到它正在转换 rowid 列 (ResultSet.getLong())。但是,返回的 ActiveRecord 对象不包括 rowid 值。我相信这是因为当 JDBC 驱动程序被要求提供用于建立 ActiveRecord 类的可用属性的表模式时,不会返回 rowid。任何意见表示赞赏...

在获取信息方面做得很好。顺便说一句,我对 JDBC 驱动程序可能正在做什么的知识开始用尽 - 这可能需要 IBM/Informix 技术支持。各种问题出现在我的脑海中——我什至不确定问题出在 JDBC 驱动程序、整体 JDBC 设计还是位于 JDBC 之上的问题上;我无论如何都不是该领域的专家。 (我会拼写 Java - C;对吗?)

您是否尝试过将 ROWID 放入语句的最后一列?

SELECT *, ROWID FROM WhereEver

给它起别名怎么样?

SELECT *, ROWID AS T_RowID FROM WhereEver

如果 JDBC 驱动程序看穿了这两个方面,那么它工作太辛苦了,对每个人都不利。事实上,我什至不确定我是否知道它是如何与视图一起工作的。

我有一个元素表:

CREATE TABLE elements
(
    atomic_number   INTEGER NOT NULL UNIQUE CONSTRAINT c1_elements
                    CHECK (atomic_number > 0 AND atomic_number < 120),
    symbol          CHAR(3) NOT NULL UNIQUE CONSTRAINT c2_elements,
    name            CHAR(20) NOT NULL UNIQUE CONSTRAINT c3_elements,
    atomic_weight   DECIMAL(8,4) NOT NULL,
    stable          CHAR(1) DEFAULT 'Y' NOT NULL
                    CHECK (stable IN ('Y', 'N'))
);

INSERT INTO elements VALUES(  1, 'H',   'Hydrogen',        1.0079, 'Y');

我能够在该表上创建一个包含 ROWID 的视图,然后对其进行查询:

CREATE VIEW x_elements(atomic_number, symbol, name, x_rowid)
    AS SELECT atomic_number, symbol, name, ROWID AS x_rowid
         FROM elements;

SELECT * FROM x_elements WHERE x_rowid <  512;
SELECT * FROM x_elements WHERE x_rowid >= 512;

这两个查询产生了不相交的数据集。你也许可以利用你的系统来利用它。如有必要,您将重命名基表(例如,“WhateverTable”变为“Base_Whatever”),然后创建视图“WhateverTable”以从 Base_Whatever 中选择数据以及 ROWID。我还没有用 JDBC 程序正式尝试过这个,但它“应该”工作(但由于原始查询也“应该”工作,我不确定我对“应该工作”断言的依赖程度)。

【讨论】:

数据库已经安装在多个位置,并且已经编译了应用程序(源不可用),如果数据库模式发生变化,这些应用程序会中断,所以我无法添加合法的主键。这些应用程序依赖 rowid 作为主键。 使用 log4jdbc 我能够确认发送到 Informix 的查询确实包含对 rowid 的请求。该值被返回并且 JDBC 驱动程序转换 ResultSet 中的每一列;我可以看到它正在转换 rowid 列 (ResultSet.getLong())。但是,返回的 ActiveRecord 对象不包括 rowid 值。我相信这是因为当 JDBC 驱动程序被要求提供用于建立 ActiveRecord 类的可用属性的表模式时,不会返回 rowid。任何意见表示赞赏... 谢谢!我认为最终的问题在于 ActiveRecord 如何处理来自显式请求 rowid 的查询的返回。我将逐步检查 ActiveRecord 并尝试找到一个扩展点,让它相信 rowid 在表的元数据中(或类似的东西 - 还不确定......) QZG,你找到解决办法了吗?我有一个和你非常相似的问题要解决。谢谢。

以上是关于如何从 ActiveRecord 访问隐藏列(在 Informix 中)的主要内容,如果未能解决你的问题,请参考以下文章

停止 Activerecord 加载 Blob 列

如何在我的助手而不是视图中循环访问 ActiveRecord_Relation?

如何禁用某个列的 ActiveRecord 日志记录?

如何隐藏列(GridView)但仍访问其值?

使用 ActiveRecord 语法从 Rails 中的连接表中选择或按列排序

如何检查 ActiveRecord 使用的数据库名称