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.
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've got 3 classes:
class Author {
static hasMany = [books: Book]
static belongsTo = [company: Company]
String name
}
class Book {
static mapping = {
collection "documents"
id generator: 'assigned',index: true, indexAttributes:[background:true, unique:true, dropDups:true]
}
String id
String name
}
class Company {
static mapping = {
collection "documents"
id generator: 'assigned',index: true, indexAttributes:[background:true, unique:true, dropDups:true]
}
String id
String name
}
I want to use
Author author = Author.getByCompanyAndBook(1,1);
but when running this Grails retrieves all the Book objects from the database.
I need those Books only as identifiers for the Author and I am not going to use those objects.
Is there a way for me to force Grails not to fetch the Books and Companies from the database?
I tried to use:
static mapping = {
books lazy: true
}
but still all of the Books and the Company were loaded.
Edit:
I am using mongo db as my database.
That's weird - collections are lazy by default, so getting an author shouldn't retrieve anything in the books collection until you access the books property. But regardless, even if it worked as expected I recommend that you avoid mapped collections. See this talk which shows why collections are unnecessarily expensive and provides workarounds to minimize the costs.
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
I have a Grails domain class that is a hierarchy of categories. Each Category has a parent category (except for the root category which is null).
class Category {
String name
static mapping = {
cache true
name index:'category_name_idx'
}
static belongsTo = [parent:Category]
static constraints = {
parent(nullable:true)
}
}
My problem: deletes cascade exactly opposite of what I'd expect:
someSubCategory.delete() deletes the category then tries to delete the parent category (which fails with an integrity violation if the parent has other children).
parentCategory.delete() does NOT cascade delete its children, but instead just fails with an integrity violation.
What am I doing wrong? My understanding is that the 'belongsTo' above should tell the GORM to cascade deletes from the parent to all children, but not from a child to its parent.
If I am understanding correctly a Category belongs to a parent and a parent can have multiple children, so I think you need a hasMany relationship, something like this:
class Category {
String name
static mapping = {
cache true
name index:'category_name_idx'
}
static belongsTo = [parent:Category]
static hasMany = [children: Category]
static constraints = {
parent(nullable:true)
}
}
I had had similar structures and never have issues with the delete doing it this way.
Hope this helps!
It's not an answer, but I found a workaround to my own question. You can remove the belongsTo = [parent:Category], replacing it with a simple instance variable. This stops subCategory.delete() from cascading to the parent.
class Category {
String name
Category parent
static mapping = {
cache true
name index:'category_name_idx'
}
static constraints = {
parent(nullable:true)
}
}
Have been trying to look for an answer for hours, but have so far not managed to come up with an adequate solution, so I'm hoping someone here might have some more experience with Grails, and implementing custom relationships in it.
My problem is that I have two classes:
Company
OrderConfig
OrderConfig contains two references to Company. 1 for a consignee, 1 for a shipper. I implemented the relationship (see below), and everything looks dandy, with my order_config table containing both a consignee_company_id column and a shipper_company_id column.
However, I do not want or need a company_id column at all. I would prefer using the CompanyName as the identifying column. How can I prevent Grails from automatically adding the id column to the company table, and instead use the companyName column as the primary key, thus ensuring my order_config table will be generated containing the companyName and not the company_id?
I tried embedding the company in the orderconfig class, and wrestled with all kinds of other options including the mappings, however I ran into trouble with each and every one of them.
Thanks in advance!
My code so far:
class OrderConfig {
static hasMany = [consignee:Company, shipper:Company]
String toString() {
return "${consignee}"
}
static constraints = {
consignee (blank:false, maxSize:10)
shipper (blank:false, maxSize:10)
}
Company consignee
Company shipper
}
class Company {
String toString() {
return "${companyName}"
}
static constraints = {
companyName(blank:false, maxSize:10)
companyAddress1(blank:false, maxSize:40)
companyAddress2(blank:false, maxSize:40)
companyAddress3(blank:false, maxSize:40)
companyAddress4(blank:false, maxSize:40)
companyZipCode(blank:false, maxSize:36)
companyCountry(blank:false, maxSize:36)
}
String companyName
String companyAddress1
String companyAddress2
String companyAddress3
String companyAddress4
String companyZipCode
String companyCountry
}
You need to look at the advanced GORM config options in the documentation, in section 5.5.2.1
There is an example
class Person {
String firstName
static hasMany = [addresses:Address]
static mapping = {
table 'people'
firstName column:'First_Name'
addresses joinTable:[name:'Person_Addresses', key:'Person_Id', column:'Address_Id']
}
}
there you can see how they are specifying the key and column name on which to do the stuff.
Edit -- I reread your question: if you are asking how to change it so Company has an assigned id, you might be able to do something like this example
static mapping = {
id generator:'assigned', column:'column_name',name:'propertyName'
}
where more options are available here: http://www.grails.org/doc/1.3.x/ref/Database%20Mapping/id.html