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'
}
}
}
}
Related
I needed to create a custom join table to re-model a many-to-many mapping and following some great posts on here came up with the model below.
Now my question is, if I have either a Course or Journey object in a GSP, how do I access the extra column data belonging to the join table.
In this example, I want to access the field named extraColumn1 in the CourseJourneyDetail within my GSP if I have either a journey or course instance
I've tried the following :
${course.courseJourneyDetail.extraColumn1}
but it didn't work.
Here are (relevant parts of) my domain classes :
class Course {
static hasMany = [journies: CourseJourneyDetail]
String courseName
String organisersDescription
Set<Journey> getJournies() {
return CourseJourneyDetail.findAllByCourse(this)*.journey
}
}
class Journey {
static hasMany = [courses: CourseJourneyDetail]
java.util.Date dateCreated
java.util.Date lastUpdated
boolean enabled = true
User user
Set<Course> getCourses() {
return CourseJourneyDetail.findAllByJourney(this)*.course
}
}
class CourseJourneyDetail implements Serializable {
String extraColumn1
static belongsTo = [course: Course, journey: Journey]
boolean equals(other) {
if (!(other instanceof CourseJourneyDetail)) {
return false
}
other.journey?.id == journey?.id &&
other.course?.id == course?.id
}
int hashCode() {
def builder = new HashCodeBuilder()
if (course) builder.append(course.id)
if (journey) builder.append(journey.id)
builder.toHashCode()
}
static constraints = {
}
static mapping = {
version false
id composite: ['course', 'journey']
}
}
Since you've established that each Course/Journey has a collection of CourseJourneyDetail's rather than a single instance, ${course.courseJourneyDetail.extraColumn1} won't work (as you've discovered).
If you break down your groovy expression into this: course.courseJourneyDetail, it doesn't really make sense based on the relationships you have created. The reason being, Course doesn't have a single CourseJourneyDetail but rather a collection.
If your desire is to have Course and Journey in a one-to-one relationship, but with a join table with additional columns, then your domain structure needs to change to reflect this: rather than using static hasHany in each class, you would switch to a single instance.
If your desire is to keep the many-to-many relationship, then you need to think about how to fetch the appropriate join object that represents the association. One example:
CourseJourneyDetail.findAllByCourseAndJourney(<courseInstance>, <journeyInstance>)
If you want the additional columns collected for all of the many-to-many associations, you can use a syntax that you are already using in your convience methods (getJournies and getCourses):
course.journies*.extraColumn1
This would output an array of Strings, so its usage makes less sense within a ${} expression; and more sense within a g:each. It entirely depends on how you plan on using this data.
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 4 Grails domain classes ( Domain1, Domain2, Domain3, Domain4). These domain objects map to legacy tables with exactly same set of columns. To be more precise, all of these tables have personFirstName, personLastName and personPhoneNumber columns.
The only thing different between these 4 domain classes is the table name they refer to.
Instead of copy/pasting same piece of code in four different places and just modifying this:
static mapping = {
table name:"legacy_table_name_A" <====== (only difference)
firstName column: "personFirstName"
lastName column: "personLastName"
phoneNumber column:"personPhoneNumber"
}
I was wondering if there is a way to do this all in one abstract class called MyAbstractDomainClass and have my Domain1, Domain2... extend it like this:
class MyAbstractDomainClass {
String firstName
String lastName
String phoneNumber
static mapping = {
firstName column: "personFirstName"
lastName column: "personLastName"
phoneNumber column:"personPhoneNumber"
}
}
class Domain1 extends MyAbstractDomainClass {
static mapping = {
}
}
How do I implement the static mapping for each Domain classes to have a different table name?
I am using Grails 2.4.2
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 creating a (theoretically) simple hasMany relationship within a domain class. I have two tables with a foreign key relationship between the two. Table 1's domain object is as follows:
Functionality{
String id
static hasMany = [functionalityControllers:FunctionalityController]
static mapping =
{
table 'schema.functionality'
id column:'FUNCTIONALITY_NAME', type:'string', generator:'assigned'
version false
}
}
and domain object 2
FunctionalityController
{
String id
String functionalityName
String controllerName
static mapping =
{
table 'schema.functionality_controller'
id column:'id', type:'string', generator:'assigned'
version:false
}
}
The issue I am having is that when I have the hasMany line inside of the Functionality domain object, the app won't start (both the app and the integration tests). The error is org.springframework.beans.factory.BeanCreationException leading to Invocation of init method failed; nested exception is java.lang.NullPointerException.
Any help would be appreciated.
UPDATE:
*Working Domains*:
class Functionality {
String id
static hasMany = [functionalityConts:FunctionalityCont]
static mapping =
{
table 'schema.functionality'
id column:'FUNCTIONALITY_NAME', type: 'string', generator: 'assigned'
functionalityConts( column:'functionality_name')
version false;
}
}
and
class FunctionalityCont {
String id
String functionalityName
String controllerName
static belongsTo = [functionality: Functionality]
static contraints = {
}
static mapping =
{
table 'schema.functionality_controller'
id column:'id', type: 'string', generator: 'assigned'
functionality(column:'FUNCTIONALITY_NAME')
version false;
}
}
Well 2 things...
1.I'm not sure but I guess that your domain class with the prefix 'Controller' maybe is the responsible, this is because grails is convention over configuration and by convention the controller class ends with Controller prefix and are in the controller folder, in this case is a lil' confusing
2.In GORM and in this case the relationship between objects can be unidirectional or bidirectional, is your decision to choose one, but in both cases there are different implementations, the class Functionality(btw is missing the 'class' word) has the right relationship to FunctionalityController through hasMany, but FunctionalityController doesn't knows about the relationship, so you can implement:
// For unidirectional
static belongsTo = Functionality
// For bidirectional
static belongsTo = [functionality:Functionality]
// Or put an instance of Functionality in your domain class,
// not common, and you manage the relationship
Functionality functionality
So check it out and tell us pls...
Regards
Try adding
static belongsTo = [functionality: Functionality]
to your FunctionalityController class. I suspect there is more to your error than what you've shown, but generally a hasMany needs an owning side to it. Since that is where the foreign key actually lives.