codeconsole opened a new pull request, #16222:
URL: https://github.com/apache/grails-core/pull/16222
A domain class that declares no `id` has always been given a `Long` one.
That is right for Hibernate and wrong for MongoDB, where a `String id` holding
a generated `ObjectId` needs no sequence collection and shards cleanly.
Declaring `String id` gets that, but ties the source to MongoDB — the same
class compiled against Hibernate would need `Long id` instead.
This adds a build setting that lets each domain class take the identity type
of the GORM implementation it is actually mapped with:
```groovy
// build.gradle
grails {
gorm {
defaultIdType = 'native'
}
}
```
```groovy
// grails-app/domain/example/Person.groovy — names no store
class Person {
String name
}
```
Compiled with GORM for MongoDB, `Person` is given a `String id`. Compiled
with Hibernate, it keeps `Long`. In an application using both, each domain
class gets the right type from the single setting, resolved from its `mapWith`
property. A domain class that declares an `id` keeps the type it declares.
The default is `defaultIdType = 'long'`, which is the behaviour of every
earlier release.
### How it resolves
`GormEntityTransformation` already worked out which GORM implementation an
entity belongs to, at compile time, in `pickGormEntityTrait` — from `mapWith`
plus the `GormEntityTraitProvider`s on the compilation classpath. That
resolution now also supplies the identity type, through a new default method on
the SPI:
```groovy
interface GormEntityTraitProvider {
Class getEntityTrait()
boolean isAvailable()
default Class getDefaultIdentityType() { Long }
}
```
`MongoEntityTraitProvider` returns `String`. Hibernate and Neo4j inherit
`Long`. Since the trait and the identity type now come from a single
resolution, the two cannot disagree.
The setting reaches the compiler as a system property published by the
Gradle plugin, the same way `grails { compileStatic { } }` already does — a
`CommandLineArgumentProvider` on
`GroovyCompile.groovyOptions.forkOptions.jvmArgumentProviders`, with the
effective value exposed as an `@Input` so that changing it invalidates the
compile task. A stale class file would otherwise keep the type the previous
setting asked for.
`EntityASTTransformation` now runs the discovered domain injectors before
`DefaultGrailsDomainClassInjector`. It ran that injector first, and it
unconditionally adds a `Long` id, so GORM never got to decide the type on the
`@grails.persistence.Entity` path. Each of the default injector's injections is
guarded on the property not already being present, so it still fills in
everything GORM did not.
### Limitations
- The identity type is compiled into the class. The setting reaches the
compiler through the Gradle plugin, so an IDE configured to compile without
Gradle produces `Long` ids.
- Turning this on changes the type of a column or field that already holds
data. It is a setting to choose when an application is written, not one to
switch on over an existing database.
- A domain class compiled into a published plugin jar has its identity type
fixed at plugin build time, not at consuming-application build time.
- RX entities are unchanged and keep `Long`.
- The scaffolding templates still hardcode `def show(Long id)` (and
`edit`/`delete`). That is a pre-existing gap — it already affects the `String
id` MongoDB domain classes the GORM for MongoDB guide recommends — and is left
for a separate change.
### Documentation
- `grails-data-mongodb` — new *Native Identity Types* section under
*Identity Generation*
- `grails-doc` — What's New in 8.0
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]