如何使用 ColdFusion ORM 存储整数?

How do I store an integer using ColdFusion ORM?

TL:DR;

具有外键约束的 CF ORM 组件的正确 syntax/workaround/hack 是什么?


ColdFusion + 整数

将变量存储为整数应该是一个简单的编程问题,对吧?在该语言的文档中找到适当的函数(如果您不记得它),它会说 returns: int (owtte) 并使用它。

不适用于 ColdFusion。

有些人可能已经知道 ColdFusion 的 various issues with integers,但目前导致我快速脱发的是 ColdFusion 有时会将您的 "integer" 存储为字符串、双精度或长。现在,对于大多数用例来说,这不是一个破坏功能的问题,而且通常是 overlooked/ignored/undiscovered。就我而言,例外情况是 ORM 开始发挥作用时。当然,就像任何明智的开发人员一样,我认识到这可能归结为某处的用户错误。


问题

只要 CF 尝试与 DB 交互,就会出现问题。如果有一个字段是外键并且类型为 'integer',CF 将抛出一个 Hibernate 异常并显示以下消息:

java.lang.Integer

就是这样。有帮助,对吧?我发现这个 "error message" 明确是您传递给该字段的变量类型,因此如果您错误地将双精度传递给该字段,错误消息将显示为 java.lang.Double.

现在,这似乎与字段本身无关,而与相关组件有关 - 这仅发生在具有外键约束的字段上,该外键约束将其链接到其他地方的整数字段。

我想要做的事情的基本示例:

Template.cfc

component persistent="true" table="template"{

    property name="id"              type="numeric"  sqltype="integer"   column="templateID" fieldtype="id"  generator="identity";
    property name="userID"          type="numeric"  sqltype="integer"   fkcolumn="userID"           fieldtype="many-to-one" cfc="User";
    property name="lastModified"    type="date"     sqltype="timestamp" column="lastModified";

}

User.cfc

component persistent="true" table="user"{

    property name="id"          type="numeric"  sqltype="integer"   column="userID"     fieldtype="id" generator="identity";
    property name="username"    type="string"   sqltype="nvarchar"  column="username";
    property name="password"    type="string"   sqltype="nvarchar"  column="password";

}

刷新已更新的 ORM 时出现问题 template.userID


我尝试过的事情

我怀疑这可能与 Hibernate 和 CF 的组合有关,而不仅仅是 CF,尽管它是 javascript- 令人怀念的怪癖,但我仍然喜欢它。


环境

TL:DR;

传递实体,而不是 ID。 引用持久实体 Foo 的 CF ORM 中的外键 属性 是 Foo 类型而不是 int。

更多详情

经过这么长时间,Adobe 让我转了几个人,直到我找到了一位知道他在说什么的工程师。事实证明,问题不在于 ORM 引擎(Hibernate)不能将整数识别为整数,而是如果你有一个引用另一个持久实体的外键,那么你必须传递 实体 而不是 ID。

示例(在问题的上下文中)

首先,我从问题中删除了 typesqltype 值,因为前者可以通过检查数据库的 CF 检索(在我的情况下这很好,但你可以必须明确设置它,特别是如果您在 Application.cfc).

中关闭了 useDBforMapping

其次,我已将模板组件中的 userID 属性 重命名为 user,因为它可能会帮助那些不能立即理解我上面所说的关于 'passing the entity' 更好地形象化它。

Template.cfc

component persistent="true" table="template"{

    property name="id"              column="templateID"      fieldtype="id"          generator="identity";
    property name="user"            fkcolumn="userID"        fieldtype="many-to-one" cfc="User";
    property name="lastModified"    column="lastModified";

}

User.cfc

component persistent="true" table="user"{

    property name="id"          column="userID"     fieldtype="id" generator="identity";
    property name="username"    column="username";
    property name="password"    column="password";

}

因此,假设您知道与此模板关联的用户的 ID(例如,他们可能是创建者)。您要做的是,不要将 ID 传递给 user 属性,而是创建一个用户组件,然后传递 that.

index.cfm

userID = 4; // Example user ID, which we got from somewhere earlier in the code

templateID = 20; // Example template ID, which we got from somewhere earlier in the code

// Create template entity (loading by primary key)
template = EntityLoadByPK( 'Template', templateID );

// To set the user in the Template entity, we must pass a User entity
user = EntityLoadByPK( 'User', userID );

// Only then can we successfully update the template's foreign key property
template.setUser( user );
EntitySave( template );

// Line below is not usually needed, but it forces DB interaction so it's 
// useful in the context of this example
ORMFlush();

希望这对遇到同样困惑的其他人有所帮助。

JC