Question

I have the following classes:


class Catalog {
  static mapping = {
    id composite:['name', 'manufacturer']
    columns {
      name column:'cat_name'
      manufacturer column:'manuf_id'
    }
  }
  String name
  Manufacturer manufacturer
}

class Order {
  static mapping = {
    columns {
      // How to rename foreign keys as cat_name, manuf_id?
    }
  }
  Catalog catalog // creates catalog_name, catalog_manufacturer_name
}

Presently, an Order table is generated with the attributes catalog_name and catalog_manufacturer_name (which reference the composite primary keys of the Catalog table).

I need to rename these generated columns to cat_name and manuf_id in the Order table to work with an existing database. Is this possible, and if so, how?

Was it helpful?

Solution

It's not possible using GORM configuration, but you can do it with a custom Configuration class:

package com.foo.bar;

import java.util.Collection;
import java.util.Iterator;

import org.codehaus.groovy.grails.orm.hibernate.cfg.DefaultGrailsDomainConfiguration;
import org.hibernate.MappingException;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.RootClass;

public class CompositeAwareHibernateConfiguration extends DefaultGrailsDomainConfiguration {

   private static final long serialVersionUID = 1;

   private boolean _alreadyProcessed;

   @SuppressWarnings("unchecked")
   @Override
   protected void secondPassCompile() throws MappingException {
      super.secondPassCompile();

      if (_alreadyProcessed) {
         return;
      }

      for (PersistentClass pc : (Collection<PersistentClass>)classes.values()) {
         if (pc instanceof RootClass) {
            RootClass root = (RootClass)pc;
            if ("com.foo.bar.Order".equals(root.getClassName())) {
               for (Iterator iter = root.getTable().getColumnIterator(); iter.hasNext(); ) {
                  Column column = (Column)iter.next();
                  if ("catalog_name".equals(column.getName())) {
                     column.setName("cat_name");
                  }
                  else if ("catalog_manufacturer_id".equals(column.getName())) {
                     column.setName("manuf_id");
                  }
               }
            }
         }
      }

      _alreadyProcessed = true;
   }
}

Put the class in src/java and register it in DataSource.groovy:

dataSource {
   pooled = true
   driverClassName = ...
   username = ...
   password = ...
   configClass = com.foo.bar.CompositeAwareHibernateConfiguration
}

OTHER TIPS

This solved my problem (grails 2.0.4):

http://jira.grails.org/browse/GRAILS-4504?focusedCommentId=64996&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-64996

My case:

class GroupMessage implements Serializable {

    Group group
    Integer messageId

    static mapping = {
        datasources(['ds1'])
        table 't_group_msg'
        version false
        id composite: ['group', 'messageId'], generator: 'assigned'
        group column:'grpid'
        messageId column:'msgid', type:int
    }
}

class GroupMessageDetail implements Serializable {

    GroupMessage groupMessage
    Integer detailId
    String message
    String url

    static mapping = {
        datasources(['ds1'])
        table 't_group_msg_det'
        version false
        id composite: ['groupMessage', 'detailId'], generator: 'assigned'
        columns {
            groupMessage {
                column name: 'grpid'
                column name: 'msgid'
            }
            detailId column:'id', type:int
            message column:'sms'
            url column:'url'
       }
}

I have write a solution that is for any domain-class that need it and you don't need readapt every time.

class Catalog {
  static mapping = {
    id composite:['name', 'manufacturer']
    columns {
      name column:'cat_name'
      manufacturer column:'manuf_id'
    }
  }
  String name
  Manufacturer manufacturer
}

class Order {
  Catalog catalog
  static mapping = {
  }
  static foreigners = [
    catalog : [name : "catalog_name",
              manufacturer: "catalog_manufacturer_name"]
  ]
}

This is the GORM Configuration class that i write to consume the foreigners in the domain class.

package my.app.package
import java.util.Collection;
import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsAnnotationConfiguration;
import org.hibernate.MappingException;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.ForeignKey;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.RootClass;
class MyCustomGrailsAnotationConfiguration extends GrailsAnnotationConfiguration{
    private static final long serialVersionUID = 1;
    private boolean _alreadyProcessed=false;
    @SuppressWarnings("unchecked")
    @Override
    protected void secondPassCompile() throws MappingException {
        super.secondPassCompile();
        if(_alreadyProcessed){
            return;
        }
        classes.values().each{rootClass ->
            if(rootClass instanceof RootClass){
                def domainClass= null
                Boolean hasForeigners=false
                try{
                    domainClass=Class.forName(rootClass.entityName,false,Thread.currentThread().getContextClassLoader())
                    hasForeigners = domainClass.metaClass.hasProperty(domainClass, 'foreigners')
                }catch(Exception e){}
                if(domainClass && hasForeigners){
                    rootClass?.table?.foreignKeyIterator?.each{fKey->
                        fKey?.columnIterator?.each{column->
                            domainClass.foreigners?.each{attrName,columns ->
                                columns.each{columnItmName,columnItmValue->
                                    def exp=attrName+"_"
                                    columnItmName.split("").each{exp+=(it==~/[A-Z]/) ? "_"+it:it}
                                    exp=exp.toLowerCase()+".(id)\$"
                                    //println "Expression:"+exp
                                    if(column.name.matches(exp)){
                                        //println "Match:"+column.name+" changing to "+columnItmValue
                                        column.name=columnItmValue
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        _alreadyProcessed = true;
    }
}

Put the my.app.package.MyCustomGrailsAnotationConfiguration.groovy class in src/groovy/my/app/package/MyCustomGrailsAnotationConfiguration.groovy and register it in DataSource.groovy:

dataSource {
   pooled = true
   driverClassName = ...
   username = ...
   password = ...
   configClass = my.app.package.MyCustomGrailsAnotationConfiguration
}

I hope that will useful for you. Thanks @carlosmain for your help

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top