GORM 映射宣言 :: 太长或不太长

发布于 2024-12-07 08:53:17 字数 1093 浏览 0 评论 0原文

相当基本的问题,但它的根源深深植根于框架中(并且关于该主题的明确信息很少),因此我将其放在这里,以减轻其他人的痛苦(并验证我的想法是否正确) )。

问题是什么?

Grails 会自动将 Long 类型的 id 字段注入到您的域中 (请参阅 Beckwith 的评论)。当使用旧版数据库时,Grails 默认将 Long 映射到 bigint,这是一种低效的存储类型,任何处理超过百万条记录的表的人都会避免这种低效的存储类型。

几个月前发现这一点后,我开始努力为我的域 ID 找到一个“正确的”列类型。没有Java背景,我盲目地认为,Long-bad,Integer-good,并将整数类型的hibernate映射方言设置为我在mysql中手动执行的操作

registerColumnType(Types.INTEGER, 'mediumint unsigned')

然后在我的所有域中定义“Integer id”(根据上面链接中的 Bert 评论,这不是必需的)。一切都进展顺利、美妙,其他事情也是如此。

快进到 Grails 2.0(因为我无法抗拒所有的好处;-))和 Spock。我一生都无法弄清楚为什么,尽管 2.0 新的内存 GORM 和对动态查找器的支持,Domain.findByFoo(fooVal) 总是返回 null(是的,我 @Mock(Domain) 并填充测试数据)。事实上,在测试本身和 @TestFor 目标中,唯一有效的 GORM 方法是 save() 和 get();其他一切都返回 null。

我制作了一个快速测试应用程序,域 + 控制器 + spoc 规范,并发现了问题的根源:如果您使用 Long 以外的属性类型作为您的 id(包括引用的 FK),您的 @Mock 域将被渲染无用。

那么,我说必须使用长 ID 才能充分利用该框架是否正确? @Mock + @TestFor + Spock 是一个令人难以置信的组合!在我踏上重构之路之前,感谢您的指导......

Fairly basic problem but it's roots run deep in the framework (and there is little definitive information on the subject), so I am putting it out here so as to save others the pain (and to verify that I am correct or not in my thinking).

What is the problem?

Grails automatically injects an id field of type Long into your domains (see Beckwith's comment). When using a legacy DB Grails maps Longs to bigints by default, an inefficient storage type that anyone dealing with large million+ record tables would avoid.

Upon discovering this a few months ago I set to work on getting a "proper" column type in place for my domain ids. Not having a Java background, blindly I thought, Long-bad, Integer-good and set hibernate mapping dialect for Integer types to what I would do by hand in mysql

registerColumnType(Types.INTEGER, 'mediumint unsigned')

and then defined "Integer id" in all of my domains (not necessary according to Bert's comment in link above). Everything worked swimmingly, wonderful, on to other things.

Fast forward to Grails 2.0 (as I could not resist all of the goodies ;-)) and Spock. For the life of me I could not figure out why, despite 2.0 new in-memory GORM and support for dynamic finders, that Domain.findByFoo(fooVal) would always return null (yes, I @Mock(Domain) and populate with test data). In fact, both within the test itself and @TestFor target, the only GORM methods that worked were save() and get(); everything else returned null.

I whipped up a quick test app, domain + controller + spoc spec and discovered the source of the problem: If you use a property type other than Long for your ids (including referenced FKs), your @Mock domain(s) will be rendered useless.

So, am I correct or not in saying that one must use Long ids in order to take full advantage of the framework? @Mock + @TestFor + Spock is an incredible combo! Guidance appreciated before I head down refactor-to-Long road...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

反目相谮 2024-12-14 08:53:17

我无法想象任何现实的场景,其中 Integer 和 Long 之间的差异会对性能产生任何明显的差异(这似乎是进行此更改的原始动机)。

如果使用 Long 有效,但 Integer 会导致问题,则使用 Long 并转向更重要的任务。只有当您能够证明使用 Integer 会产生显着差异时,我才会担心这一点。

更新

你是对的,我确实完全忽略了 Grails 自动使用 Long 的数据库类型的要点。正如您似乎已经知道的那样,您可以在域类的映射闭包中控制数据库类型,例如

class Person {
   Long id

   static mapping = {
      // See here for alternatives to integer, and how they map to DB types
      // http://docs.jboss.org/hibernate/stable/core/manual/en-US/html/mapping.html#mapping-types-basictypes
      id type:'integer'
   }
}

您还在评论中提出

在代码级别处理 Long,必须指定 def foo(Long id) {...} 和 params.id.toLong() 而不是 Integer

您可以简单地将操作定义为

def myAction = {Person p ->

}

or

def myAction = {
   Person p = new Person(params)
}

并且 Grails 将负责类型转换Person.id 的 id 请求参数,无论它是 Long、Integer、BigDecimal 等。

I cannot imagine any realistic scenario where the difference between Integer and Long would make any noticeable difference to performance (which seems to have been the original motivation for making this change).

If using Long works, but Integer causes problems, then use Long and move onto more important tasks. I would only worry about this if you can prove that using Integer makes any significant difference.

Update

You're right, I did completely miss the point about the database type that Grails automatically uses for Long. As you seem to already know, you can control the database type in the mapping closure of your domain class, e.g.

class Person {
   Long id

   static mapping = {
      // See here for alternatives to integer, and how they map to DB types
      // http://docs.jboss.org/hibernate/stable/core/manual/en-US/html/mapping.html#mapping-types-basictypes
      id type:'integer'
   }
}

You also brought up in the comments

dealing with Long at code level where one must specify def foo(Long id) {...} and params.id.toLong() as opposed to Integer

You can simply define an action as

def myAction = {Person p ->

}

or

def myAction = {
   Person p = new Person(params)
}

And Grails will take care of type-converting the id request parameter to Person.id, regardless of whether it's a Long, Integer, BigDecimal, etc.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文