I have a tRNA class which may or may not have an associated grRNA, but will be associated to cRNA.
So I can have this relationship :
tRNA -> grRNA -> cRNA
Or this relationship (in this case we don't have grRNA data) :
tRNA -> cRNA
What is the best way to implement this relationship (we may not have grRNA sometimes) via Grails/Gorm ?
Best domain class design ?
You could have grRNA and cRNA be subclasses of a parent, with tRNA having an association with the parent, and grRN associating with cRNA.
In your database tables you would need a class column to define the class (discriminator in the GORM object).
Edit:
Something like:
class GenericRna {
//Properties
//Assuming this is mapped to a database table as well, you'd need:
static mapping = {
table 'generic_rna'
discriminator column: 'class'
}
}
class CRna extends GenericRna {
//Properties
discriminator value: 'CRna'
}
class GrRna extends GenericRna {
//Properties
static hasMany = [cRnas: CRna]
discriminator value: 'GrRna'
}
class TRna {
static hasMany = [genericRnas: GenericRna]
}
Technically I believe that if you use 'class' as your discriminator column name, and the class names as the values, you do not need the 'discriminator' lines.
Related
With Grails 3.2.5, hibernate 5.1.2 core.
I have a legacy database that has several clobs in a table. In order to avoid eager fetching, in earlier versions of Grails I defined a domain class that contained only those clobs in order to make them accessed via an (apparent) association which could then be lazily fetched. A sketch of the setup:
class Comment {
String someField // eager
CommentText cmntText // lazy
static mapping = {
id column: 'COMMENT_ID', generator:'sequence', params:[sequence:'cmnt_seq']
}
In a separate domain class file:
class CommentText {
String userComment
static mapping = {
table 'COMMENT'
id generator:'assigned'
userComment sqlType:'clob'
}
As noted, clob column 'user_comment' exists in the single table 'COMMENT'.
In 3.2.5, when doing this I get an error that column 'comment_text_id' is not defined in table 'comment'. This didn't use to be the case, nor should the field have to exist.
On a similar note, in another case I define a composite domain class (a class defined in the same file as the actual domain class). In this case too I get an error about a missing id:
class A {
B b
}
class B {
String someField
}
In this case I get an error saying that field b_id is not in table 'A'. But - it's supposed to be embedded composition, it should not be there.
I'm building within Intellij if that is relevant.
With GORM 6.1 this is now possible with a single domain class
import grails.gorm.hibernate.annotation.ManagedEntity
import static grails.gorm.hibernate.mapping.MappingBuilder.*
#ManagedEntity
class Comment {
String someField
String userComment
static constraints = {
}
static final mapping = orm {
id {
generator("sequence")
params(sequence:'cmnt_seq')
}
userComment = property {
lazy(true)
column {
sqlType 'clob'
}
}
}
}
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()
I have an Abstract Class which all DomainClasses are extending.
This Abstracte Class looks like this:
abstract class DomainBase {
Date created = new Date(), modified = new Date()
User createdBy, modifiedBy
int dataStatus = 30
}
My DomainClass User also extends the abstract Class and has multiple self-referencing relationship:
User principal
static hasMany = [employees: User, skills: UserSkill,...]
static mappedBy = [employees: 'none' ]
UserSkill:
class UserSkill extends DomainBase {
String category
String name
static belongsTo = [User]
static hasMany = [users: User]
static mappedBy = [users: 'skills']
static mapping = {
table 'skill'
users column: 'skill_id', joinTable: 'user_skills'
}
}
With that i'm getting an MappingException:
nested exception is org.hibernate.MappingException: broken column mapping for:
createdBy.skills of: de.streit.user.UserSkill
How do I mapp the classes correctly?
Stepping away from Grails for a moment... you've got an object-oriented design problem. According to your design, DomainBase sits at the top of your hierarchy. Because of this DomainBase should not depend on its subclasses. Here's why:
According to the Liskov substitution principle, if class B extends from class A, then an instance of class B should be usable wherever an instance of class A is expected.
For example, if class Duck extends class Bird, I can honestly say a Duck is a Bird. My nose would not get any longer. If a method expects a Bird and I give it a Duck the method won't know the difference.
In your case, a User cannot be a DomainClass because a DomainClass has a user. Can a Bird have a Duck? Nope. A Bird should not know anything about Ducks. Animals aside, your class hierarchy violates this principle. But this can be fixed :)
Solution
As long as you're using Groovy 2.3 or grater, a Groovy trait can address your issue.
First, create a trait somewhere in grails-app/src/main/groovy/. It's best if you place it in the same Groovy (Java) package as your domain classes.
package xzy
trait Auditable {
Date created = new Date(), modified = new Date()
User createdBy, modifiedBy
int dataStatus = 30
}
Then, have your domain classes implement the trait.
package xyz
class User implements Auditable {
User principal
static hasMany = [employees: User, skills: UserSkill,...]
static mappedBy = [employees: 'none' ]
}
class UserSkill implements Auditable {
String category
String name
static belongsTo = [User]
static hasMany = [users: User]
static mappedBy = [users: 'skills']
static mapping = {
table 'skill'
users column: 'skill_id', joinTable: 'user_skills'
}
}
This works because your domain classes will magically get the properties defined in the trait (created, createBy, and dataStatus) without baggage of inheritance. Plus, if a method expects an Audiable, you can pass it a User or UserSkill and the method wouldn't know the difference.
Watch this: Users and UserSkills are Auditable. Makes sense huh?
Permanently I have some tables and some hibernate classes with mapping annotations. And this classes have abstract superclass with mapping annotations also. But in this superclass there is no table association mapping. All tables are identified in the subclasses.
I'm trying to migrate this mapping to GORM model. But all strategies: TablePerHierarchy and TablePerSubclass not approach for my case because all tables is created and can't be changed.
I created superclass in the 'src/groovy/somepackage/' and want to inherit mapping and constraints from this class to my subclasses in the 'domain' folder. For constraints it works good but for mapping I can't find documentation how to do this.
Does anyone have any ideas?
Example.
In the non-domain folder:
absract class A {
String a
static mapping = {
a column: "column_A"
}
}
In the domain folder:
class B extends A {
String b
static mapping = {
b column: "column_B"
}
}
And
class C extends A {
String c
static mapping = {
c column: "column_C"
}
}
Needs to get two tables with the column 'column_A' in each of them.
It's possible using the clone and delegate features. Here's what I did:
class B extends A {
static mapping = {
def copyMapping = A.mapping.clone()
copyMapping.delegate = delegate
copyMapping.call()
}
}
This can now be done a bit more straight forwardly:
class B extends A {
static mapping = {
includes A.mapping
}
}
I'm a newbie in grails. i'm having a problem right now in my domain classes. I have 3 domain classes, class Patient,class Nurse and class NursePatient, the class NursePatient is a composite key where you can see who is the attending Nurse in a Patient, so if you view its table you can only see the id's of nurses and patients. This is my code for Nurse class:
class Nurse {
String name
Nurse partner
boolean idle = true
static belongsTo = [hospital: Hospital]
static constraints = {
name(blank:false)
partner(nullable:true)
hospital(nullable:false)
}
String toString(){
"Nurse ${name}"
}
}
--> and this is my domain class for NursePatient:
class NursePatient implements Serializable{
Nurse nurse
Patient patient
static mapping = {
version false
id composite:['nurse', 'patient']
}
static constraints = {
patient(nullable:false, validator:{val, obj -> val.hospital == obj.nurse.hospital})
nurse(nullable:false)
}
String toString(){
"Nurse ${nurse.name} - ${patient.name}"
}
void saveIt(Nurse x, Patient y){
def np = new NursePatient(nurse: x, patient: y)
if(np.save()){
def n = nurse.get(nurse.id)
n.idle = false
}
}
}
--> I was asked to print a list of nurses who doesn't have a patient. I was thinking that the moment I save in table using the saveIt() method from class NursePatient, once the save() is successful it changes the value of the property idle of class Nurse from true to false so that querying is much more easier. My problem is I don't if my code in class NursePatient is correct or is it possible to change the value of a property from another class. Please Help me.. thank You!!
Changing properties of domain classes inside different classes is fine.
However, you don't really need a NursePatient class. If you declare the relationship between Nurses and Patients as many-to-many, like this:
class Nurse {
static hasMany = [patients: Patient]
...
}
class Patient {
static hasMany = [nurses: Nurse]
...
}
then Grails will create and update the needed join table automatically. You can then query for all the nurses without patients using Criteria API:
def nursesWithoutPatients = Nurse.withCriteria { isEmpty("patients") }