简体   繁体   中英

How do you specify a join table's name and columns in a Grails 4 domain class?

I'm currently upgrading a Grails 4.0.1 application to Grails 4.0.11 and I'm running into an issue with the join tables for one of my domain classes.

My Account class has multiple hasMany relationships with my class CompletionStatus :

import grails.compiler.GrailsCompileStatic
import grails.gorm.hibernate.mapping.MappingBuilder

@GrailsCompileStatic
class Account {

    String name

    static hasMany = [successCompletionStatuses: CompletionStatus, noShowCompletionStatuses: CompletionStatus,
            partialSegmentAttendanceCompletionStatuses: CompletionStatus]

    // Have distinct join tables for the CompletionStatus associations
    // https://github.com/grails/grails-core/issues/10811#issuecomment-337931115
    static mapping = MappingBuilder.orm {
        property('successCompletionStatuses') {
            joinTable { name "account_success_completion_statuses" }
        }
        property('noShowCompletionStatuses') {
            joinTable { name "account_no_show_completion_statuses" }
        }
        property('partialSegmentAttendanceCompletionStatuses') {
            joinTable {
                name "account_partial_completion_statuses"
                key {
                    name "account_partial_completion_statuses_id"
                }
                column {
                    name "different_completion_status_id"
                }
            }
        }
    }

    static constraints = {
        name blank: false
    }
}
import grails.compiler.GrailsCompileStatic

@GrailsCompileStatic
class CompletionStatus {

    String courseType
    String status

    static constraints = {
        courseType nullable: true
        status blank: false
    }
}

The mapping in Account works as expected in Grails 4.0.1, with multiple join tables being created in the database. However, when running the application in Grails 4.0.11 I get an error at startup which I eventually discovered can be prevented by removing the multiple hasMany relationships from Account :

Caused by: java.lang.NullPointerException: null
    at org.hibernate.mapping.Column.getCanonicalName(Column.java:362)
    at org.hibernate.mapping.Table.getColumn(Table.java:233)
    at org.hibernate.mapping.Table.addColumn(Table.java:257)
    at org.grails.orm.hibernate.cfg.GrailsDomainBinder.bindSimpleValue(GrailsDomainBinder.java:2938)
    at org.grails.orm.hibernate.cfg.GrailsDomainBinder.bindCollectionSecondPass(GrailsDomainBinder.java:450)
    at org.grails.orm.hibernate.cfg.GrailsDomainBinder$GrailsCollectionSecondPass.doSecondPass(GrailsDomainBinder.java:3406)
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1693)
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1661)
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:286)
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.build(MetadataBuildingProcess.java:83)
    at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:473)
    at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:84)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:689)
    at org.grails.orm.hibernate.cfg.HibernateMappingContextConfiguration.buildSessionFactory(HibernateMappingContextConfiguration.java:287)
    at org.grails.orm.hibernate.connections.HibernateConnectionSourceFactory.create(HibernateConnectionSourceFactory.java:86)
    at org.grails.orm.hibernate.connections.AbstractHibernateConnectionSourceFactory.create(AbstractHibernateConnectionSourceFactory.java:39)
    at org.grails.orm.hibernate.connections.AbstractHibernateConnectionSourceFactory.create(AbstractHibernateConnectionSourceFactory.java:23)
    at org.grails.datastore.mapping.core.connections.AbstractConnectionSourceFactory.create(AbstractConnectionSourceFactory.java:64)
    at org.grails.datastore.mapping.core.connections.AbstractConnectionSourceFactory.create(AbstractConnectionSourceFactory.java:52)
    at org.grails.datastore.mapping.core.connections.ConnectionSourcesInitializer.create(ConnectionSourcesInitializer.groovy:24)
    at org.grails.orm.hibernate.HibernateDatastore.<init>(HibernateDatastore.java:212)
    at sun.reflect.GeneratedConstructorAccessor64.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:175)
    ... 123 common frames omitted

I found I was able to get the database tables account_success_completion_statuses and account_no_show_completion_statuses created by specifying the mapping in Acccount like so, but I am still unable to customize the table name and column names for account_partial_completion_statuses :

static mapping = MappingBuilder.orm {
    property('successCompletionStatuses') {
        joinTable "account_success_completion_statuses"
    }
    property('noShowCompletionStatuses') {
        joinTable "account_no_show_completion_statuses"
    }
    property('partialSegmentAttendanceCompletionStatuses') {
        joinTable {
            name "account_partial_completion_statuses"
            key "account_partial_completion_statuses_id"
            // This isn't setting the column name
            column "different_completion_status_id"
            // This isn't setting the column name either
            // column { name "different_completion_status_id" }
        }
    }
}

With the mapping above, a database table named account_completion_status is created instead of account_partial_completion_statuses , and it has columns account_partial_completion_statuses_id and completion_status_id .

For more context in case it is needed, I'm using MySQL 5.6.51 and the library mysql:mysql-connector-java:5.1.48 in my application.

I found the solution in the Grails documentation on joinTable !

The join tables are created properly in the database and the application runs fine when I specify my Account class like so:

import grails.compiler.GrailsCompileStatic

@GrailsCompileStatic
class Account {

    String name

    static hasMany = [successCompletionStatuses: CompletionStatus,
            noShowCompletionStatuses: CompletionStatus,
            partialSegmentAttendanceCompletionStatuses: CompletionStatus]

    // Have distinct join tables for the CompletionStatus associations
    // https://docs.grails.org/3.1.1/ref/Database%20Mapping/joinTable.html
    static mapping = {
        successCompletionStatuses joinTable: [
                name: 'account_success_completion_statuses']
        noShowCompletionStatuses joinTable: [
                name: 'account_no_show_completion_statuses']
        partialSegmentAttendanceCompletionStatuses joinTable: [
                name: 'account_partial_completion_statuses',
                key: 'account_partial_completion_statuses_id',
                column: 'different_completion_status_id']
    }

    static constraints = {
        name blank: false
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM