GORM只读列

时间:2014-12-18 12:00:55

标签: grails triggers gorm

我们的大多数表都有一个或多个由数据库设置的列,可以是触发器,也可以使用数据库默认值(不需要在插入或更新中发送字段)

这包括以dB为单位设置的交易日期(因此所有时间都是由单个来源非常准确地标记的时间,而不是依赖于任意服务器或PC上的时间准确性。

第二个非常常见的用例是说客户记录是否有他的地址和最后一个登录字段。最后登录的字段(以及失败的登录次数)由系统的另一部分(例如,由网站服务器)设置。当运营商或客户编辑其地址时,GORM提供的当前过于简单的CRUD系统将覆盖这样的字段。这是因为GORM在其更新和插入语句中包含每个字段,即使它为null,或者它没有被更改。

我们需要一种方法来从插入和更新中擦除字段,但仍然在读取调用中使用它。 即一个真正的“只读”属性。

我们尝试了这个:

    failedLoggins editable: false, attributes: [readonly:true]

这对生成的SQL没有任何影响(甚至不影响脚手架的UI - 它仍然可以在创建和编辑中编辑,至少在grails 2.4.4中,但那是另一个故事)

当我们想要明确地写下其中一个字段时,例如登录失败的次数,我们将使用嵌入式SQL。

我看过这篇文章:http://grails.1312388.n4.nabble.com/Read-Only-columns-td1390025.html

提出完全相同的问题,但只提供一个解决方案,即此插件:

http://grails.org/plugin/extended-gorm-mappings

不幸的是,这个插件自2010年以来一直没有更新,只适用于1.3。我们需要一些适用于2.4.4的东西。

任何有多个编辑独立字段的系统的grails应用程序都需要这样的东西,或进行大量锁定(这通常是不可能的)。

E.g。操作员打开客户详细信息进行编辑,编辑可编辑的内容(例如地址),然后操作员在网站上登录失败(不同的grails或非grails应用程序),然后操作员保存玩家详细信息。如果保存包含numberOfFailedLogins字段,则系统将失败。如果打开播放器的详细信息以进行编辑会锁定播放器,则播放器将无法登录,因为更新“lastLoggedIn”或“numFailedLogins”将无法通过锁定进行写入。解决方案非常简单 - 只读列。另一种方法是将每个只读类型的feild放在他们自己的表中,但这将是站不住脚的(并导致数百个字段表)

或者我们回到使用MyBatis,它没有这样的问题,并且完全控制。可悲的是,没有好的mybatis插件适用于gails。

2 个答案:

答案 0 :(得分:3)

您可以将derived properties用于字符串和数字属性:

class Batch {
    String name
    Integer timesRun

    static mapping = {
        timesRun formula: 'times_run' //times_run is a column in the "batch" table
    }
}

在上面的代码中,timesRun将从数据库中读入,但在插入和更新时会被忽略,因为Hibernate会将列视为计算列。

更新了示例,因为原始示例可能具有误导性

答案 1 :(得分:0)

这可能不是专门回答您的问题,但您可以使用dynamicUpdates告诉GORM仅更新在当前会话期间已更改的域对象的属性。因此,只要您不更改代码中的“只读”属性,就不会在Grails生成的SQL更新语句中设置它。为了增加安全性,您可以覆盖(和noop)setter,以便您的代码永远不会更改该属性。

https://grails.github.io/grails-doc/latest/ref/Database%20Mapping/dynamicUpdate.html

dynamicUpdates的一个缺点是它可能使Hibernate查询缓存不那么有用。但是,似乎有些Grails / Hibernate专家建议你无论如何都要禁用查询缓存(至少在旧版本的Grails中)。不确定Grails 2.4 +是否属实