【问题标题】:Grails: Unable to add integer property to domain classGrails:无法将整数属性添加到域类
【发布时间】:2014-02-28 01:39:04
【问题描述】:

我有一个 Grails 域类,它是 SQL Server 上的相关数据库表。我想将整数类型的新属性/列 jPId 添加到现有域/表中。这是我的代码:

class JobCode{

    int jPId // This is the new property/column I want to add.

    //Other Properties which already have corresponding columns in DB

    static mapping = {
        jPId defaultValue: 0
    }

    static constraints = {
        jPId nullable:true // tried commenting this line as well
        //Other properties
    }
}

我的 DataSource 配置文件将 DB 模式设置为“更新”,因此,我可以执行任何 ALTER 操作。现在,当我重新启动服务器时,我希望它在数据库中创建新的整数/数字列。但它会抛出以下错误并且无法创建列:

ERRORorg.hibernate.tool.hbm2ddl.SchemaUpdateUnsuccessful: alter table EF_JobCode add jpid int not null
ERRORorg.hibernate.tool.hbm2ddl.SchemaUpdateALTER TABLE only allows columns to be added that can contain nulls, or have a DEFAULT definition specified, or the column being added is an identity or timestamp column, or alternatively if none of the previous conditions are satisfied the table must be empty to allow addition of this column. Column 'jpid' cannot be added to non-empty table 'EF_JobCode' because it does not satisfy these conditions.

我一无所知,因为我不知道我错过了什么!我在上面的代码中也给了 int jPId 一个默认值,并将其声明为 nullable:true (也对其进行了评论,因为我不确定 nullable:true 是否适用于原始类型)。没有任何效果,我一直看到上述错误。

【问题讨论】:

  • 您能否在映射中指定您想要的实际列名并尝试一下? jPId column: "JP_ID", defaultValue: 0?或您希望名称不是“JP_ID”的任何名称。
  • 我也尝试过使用专栏,但没有成功。令人讨厌的是,Grails 试图使用命令alter table EF_JobPremium add jpid int not null 更改表......尽管我提到了 nullable:true。
  • 这是一个 Hibernate 的东西 - 它可以保护你免受自己的伤害 - 请参阅我的答案

标签: grails grails-orm


【解决方案1】:

可空原语在 Hibernate/GORM 中没有意义。如果数据库中有空值,则在 Groovy/Java 中,零不是一个合适的值,因为零是一个有效值,并且通常与 null 非常不同,具体取决于您的业务规则。同样对于 boolean/Boolean - false 与 null 不同。始终为数字和布尔值指定对象类型,以允许数据库空值是 Groovy/Java 空值。

此外,不要使用dbCreate='update'。添加列时,无论您在约束中指定什么,它们都被添加为可为空的,并且您必须修复前面的行以具有有效值并将列更改为非空。此外,许多看似合理的更改将不会进行。一个例子是列加宽。即使这不会导致数据丢失,Hibernate 也不会这样做。它也不会添加索引,并且还有其他相关问题。使用 create-drop 直到您厌倦了每次重新启动都会丢失数据并切换到数据库迁移,例如http://grails.org/plugin/database-migration

【讨论】:

  • 我想我应该同意我宁愿选择 Wrapper 类类型而不是原语。但是,我仍然不明白为什么当我给它一个默认值时它不能接受一个 int 类型的属性。在我的情况下,0 是一个很好的默认值,我希望它与原始 int 一起使用,因为在应用程序中还有其他实例,其中一些属性在我们的创建删除状态期间被创建为“双”或“布尔”。
  • 关于 dbCreate='update',好吧,我们正处于发布的中间阶段,我没有那么奢侈的选择任何与我们团队决定的不同的东西。但是,您能否更清楚地说明为什么 create-drop 比 update 更好?当我们处理测试数据时,我们不希望每次重新启动服务器时都清理、重建和重新加载数据表,对吗?
  • 没有简单的解决方案。 create-drop 删除所有内容,但您始终保持同步,并且可以在 BootStrap 中填充数据(尽管这对于大数据是不切实际的)。您还可以保留已知良好的导出并根据需要重新导入。 update 太胆小了,会做出意想不到的事情,所以我完全避免了。迁移可能需要做很多工作,但我认为一旦你习惯了这个过程,它就不会那么糟糕了。它归结为为您的工作流程选择最不坏的选项:)
  • 如果我可能会问,为什么我不能通过在域类中定义一个新属性'Integer customId = 0'来添加一个新列?数据库仍处于 UPDATE 模式。我只能通过设置 customId nullabe:true 来创建新列。但我希望它是非空字段,所以我必须在后端更改表。我不喜欢它,因为 Grails 域会说 nullable:true 并且在后端我们将其修改为非空域。
  • 不要使用更新,使用迁移。拥有您的代码、您的数据库和您的更改。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多