grails: How to map one to many relationship with composite ForeignKey - grails

I have a pre-existing database with two tables FileContainer and FileObjects. FileContainer has a composite primary key of clientId and fileContainerId. FileContainerId is unique per client. FileObjects also has a composite primary key of clientId(FileContainerClientId) and fileObjectId. FileContainer and FileObjects has a one to many relationship. Foreign Key Relationship is having multiple columns(clientId and fileContainerId). So my Domain classes look like the following.
class FileContainer implements Serializable {
BigDecimal clientId
BigDecimal fileContainerId
...
...
static hasMany = [fileObjects: FileObject]
static mapping = {
table 't_container'
id composite : ["clientId", "fileContainerId"]
}
}
class FileObject implements Serializable {
BigDecimal FileContainerClientId
BigDecimal fileObjectId
FileContainer fileContainerId
...
...
static belongsTo = [FileContainer]
static mapping = {
table 't_file_object'
id composite : ["FileContainerClientId", "fileContainerId"]
column fileContainerId: 'custom_name_container_id'
column FileContainerClientId: 'client_id'
}
}
But unfortunately above Domain classes fails validation and give the following exception with text org.hibernate.MappingException: 'Repeated column in mapping for entity: FileObject column: file_container_client_id (should be mapped with insert="false" update="false")'.
I tried using a custom UserType consisting of columns (client_id and file_container_id). But got all sorts of different errors.
How should domain classes be created in this case ?
Also, If somebody can give an example of using org.hibernate.usertype.UserType that would be helpful.
===============================================================
Also tried the following in the FileObject class.
class FileObject implements Serializable {
BigDecimal clientId
BigDecimal fileObjectId
BigDecimal fileContainerId
...
...
static belongsTo = [fileContainer: FileContainer]
static mapping = {
table 'file_object'
id composite : ["FileContainerClientId", "fileContainerId"]
column fileContainerId: 'custom_name_container_id'
column clientId: 'client_id'
fileContainer column: 'client_id'
fileContainer column: 'file_container_id'
}
}
But got the missing file_container_client_id column exception.
=========================================================================
Since the FileContainerClientId in Object class is a foreign key to clientId in Container class, it should never be inserted or updated directly, it should always come from FileContainer class. Going by the above logic, I tried adding the following mapping
static mapping = {
FileContainerClientId insertable: false
FileContainerClientId updateable: false
}
but Compile failed since the property name starts with capital letter. If I change the property name to fileContainerClientId then it compiles but cannot map the column to foreignKey and throws a missing file_container_client_id column exception during validation

The following code can be used to map such cases.
class FileContainer implements Serializable {
BigDecimal clientId
BigDecimal fileContainerId
...
...
static hasMany = [fileObjects: FileObject]
static mapping = {
table 't_container'
id composite : ["clientId", "fileContainerId"]
}
}
class FileObject implements Serializable {
BigDecimal clientId
BigDecimal fileObjectId
BigDecimal fileContainerId
FileContainer fileContainer
...
...
static belongsTo = [FileContainer]
static mapping = {
table 't_file_object'
id composite : ["clientId", "fileObjectId"]
columns {
fileContainer {
column name:'client_id'
column name:'file_container_id'
}
}
fileContainer insertable:false, updateable:false
}
}

Related

Grails/GORM Class and subclass with composite key mapping

I need to map Domain classes and subclasses of a legacy database.
The model thath I need to recreate with Grails is to this tables:
Tables structure
CARD_PAYMET and CHEQUE_PAYMENT is subclasses of PAYMENT and share a composite key of two field: OrderId and PaymentId.
I try some ex scenarios, but I can´t arrive to solution. None of then recreate the same model data, and I can´t change this model.
Can any one help me?
Thanks.
Your database looks like a good fit for table-per-subclass inheritance. First, since you're using a composite primary key, your domain classes need to implement the Serializable interface. Then it's a matter of mapping each table column to a property.
import groovy.transform.EqualsAndHashCode
#EqualsAndHashCode(includes=['orderId', 'paymentId'])
class Payment implements Serializable {
int orderId
int paymentId
float amount
static mapping = {
version false
tablePerHierarchy false
id composite: ['orderId', 'paymentId']
orderId column: 'OrderId'
paymentId column: 'PaymentId'
/* Assuming case-insensitive db, so I left out 'Amount'. */
}
}
class CardPayment extends Payment {
String cardType
static mapping = {
version false
cardType column: 'CardType'
}
}
class ChequePayment extends Payment {
int checkNumber
static mapping = {
version false
checkNumber column: 'CheckNumber'
}
}
Note: In this example I used Groovy's EqualsAndHashCode AST transformation to implement Serializable.
With the domain classes in place you'll be able to do GORM polymorphic queries:
def payments = Payment.list() // All Payments (Payment, CardPayment, and ChequePayment).
def cardPayments = CardPayment.list() // Only CardPayments.
...
def nicePayments = Payment.where { amount > 1000 }.list()

How to create 3 domain relationships in Grails 3?

I have 3 domain class and I need to define their relationships but I find no luck in defining them correctly. Can somebody rectify my code? I have always get the error unknown column pointing to an id. Please help. Below are my codes. Thank you.
Todo.groovy class
package todoScaff
import userScaff.User
import categoryScaff.Category
class Todo {
String name
String note
Date createDate
Date dueDate
Date completedDate
String priority
String status
User owner
Category category
static belongsTo = [User, Category]
static constraints = {
name(blank:false)
createDate()
priority()
status()
note(maxsize:1000, nullable:true)
completedDate(nullable:true)
dueDate(nullable:true)
}
String toString() {
name
}
}
Category.groovy class
package categoryScaff
import todoScaff.Todo
import userScaff.User
class Category {
String name
String description
User user
static belongsTo = User
static hasMany = [todos: Todo]
static constraints = {
name(blank:false)
}
String toString(){
name
}
}
User.groovy class
package userScaff
import todoScaff.Todo
import categoryScaff.Category
class User {
String userName
String fname
String lname
static hasMany = [todos: Todo, categories: Category]
static constraints = {
userName(blank:false, unique:true)
fname(blank:false)
lname(blank:false)
}
String toString(){
"$lname, $fname"
}
}
Errors
I'm fairly certain your SQL tables are incorrect.
I created a small project with your 3 domain classes and used the grails command schema-export; after removing everything that doesn't relate to the domain relationship, the structure should look like this:
create table category (
id bigint,
user_id bigint,
);
create table todo (
id bigint,
category_id bigint,
owner_id bigint,
);
create table user (
id bigint
);
If your table structure doesn't resemble this, you should either change it to match or use the static mapping = {} closure in the domain class to indicate the proper column names.
Static Mapping
In Todo:
static mapping = {
owner column: 'owner_id' // change owner_id to match your owner column within todo
category column: 'category_id' // change category_id to match your category column within todo
}
In Category:
static mapping = {
owner user: 'user_id' // change user_id to match your user column within category
}

GORM hasMany using multiple columns

I have a class as follows
class PrefValue extends MainDomain {
String entityClass
Long entityId
....
}
I am now trying to map a collection to two different classes
class TypeA extends MainDomain {
Long entityId
static hasMany = [preferences:PrefValue]
static mappedBy = [preferences: "entityId"]
...
}
class TypeB extends MainDomain {
Long entityId
static hasMany = [preferences:PrefValue]
static mappedBy = [preferences: "entityId"]
}
The problem arises because both TypeA and TypeB can have the same ID but they will have different entityClass values. How would I map this?
I'm assuming that entityId is the primary key, leading to issues when TypeA and TypeB both have the same value for their primary key.
In this case you can drop the primary key constraint and instead use a composite primary key instead. The documentation goes into more detail about it here.
If you it is NOT a primary key and is just has a unique constraint, then you can make the entityId unique per discriminator:
static mapping = {
entityId unique: 'entityClass'
}

Creating domain classes with foreign key constraints in groovy

Hi I am trying to create a domain class with foreign key constraint to another existing domain class
New domain class is ArEntitlement defined as below
package ars
import gra.Resources
class ArEntitlement {
long id
String entitlementname
String entitlementdesc
String entitlementcomm
Integer departmentid
Resources resource
Integer version
static belongsto =[resource : Resources]
static mapping={
table 'ar_entitlement'
id(generator:'increment')
column{
id(column:'id')
}
}
}
Resource domain class is defined as follows (it was created before)
package gra
import com.gra.transaction.UserTransaction
class Resources {
Long id=1
String resourceName
Double resourceType
String resourceOwner
Double riskScore
Integer decommissioned
String resourceClass
Long resourceSegment
String targetIp
String resCriticality
Long resourceGroup
Integer disabled
static hasMany=[userTransactions:UserTransaction]
static mapping = {
table 'resource'
version false
id(generator:'increment')
column{
id(column:'id') }
}
static constraints=
{
resourceName(nullable:true,blank:false)
resourceType(nullable:true,blank:false)
resourceOwner(nullable:true,blank:false)
riskScore(nullable:false,blank:false)
decommissioned(nullable:false,blank:false)
resourceClass(nullable:false,blank:false)
resourceSegment(nullable:false,blank:false)
targetIp(nullable:false,blank:false)
resCriticality(nullable:true,blank:false)
resourceGroup(nullable:false,blank:false)
disabled(nullable:false,blank:false)
}
}
The resulting tables created dont have a foreign key mapping of ar_entitlement table to resource table, it does create a column called 'resource_id' but without foreign key constraint.
I need it to be pointing to id column of resource table
I tried several options, not having the belongsto specifier, using hasOne (in both domain classes) but not getting required foreign key relationship.
Any Idea what the issue is here?
log error i get is
2011-12-21 19:50:17,258 [main] ERROR hbm2ddl.SchemaUpdate - Unsuccessful: alter table ar_entitlement add index FKDCD6161FEFD54E5E (resourceid_id), add constraint FKDCD6161FEFD54E5E foreign key (resourceid_id) references resource (id)
Remove 'Resources resource' row from ArEntitlement.
static belongsTo = [resource : Resources]
Should cover that and having it defined twice might be the issue. Also you shouldn't need to specify the table names, the id generator or id column as it appears you are using the GORM defaults. Try removing these as well.
Here is the modified code...
package ars
import gra.Resources
class ArEntitlement {
String entitlementname
String entitlementdesc
String entitlementcomm
Integer departmentid
Integer version
static belongsTo = [resource : Resources]
static mapping = {
}
}

Grails: master domain field by detail domain field [hasMany]

There are domains:
class Order {
static hasMany = [execDepartments: Department]
String orderNo
//boolean signature
...
}
class Department {
String name
...
}
I want to add boolean signature field for Order but by Department, so I need field signature by execDepartments for Order. Is it possible? Please help.
Is this an m:m relationship?
why not create another domain like
class Order {
static hasMany = [execDepartments: DepartmentOrder]
String orderNo
//boolean signature
...
}
class DepartmentOrder{
boolean signature
Order order
Department department
}
class Department {
String name
static hasMany = [execOrders: DepartmentOrder]
}
Then you can write the belongTo
What you need is a list of signatures in the Order domain.
Possibly an OrderSignature domain that maps signatures to orders.

Resources