I'm trying to change the foreign key column name that is used in Visitor table for User's id. The column is named now user_id, I want to change that to who_id.
Minimal User Domain Class:
class User {
static hasMany = [
visitor: Visitor
]
String uid
...
}
Minimal Visitor Domain Class:
class Visitor {
static belongsTo = [user: User]
....
}
Question:
I've tried with mappedBy but with no success, is there another way to use a property from User as a foreign key in Visitor?
I think you want to use the mapping static block:
class Visitor {
static belongsTo = [user: User]
static mapping = { user column: 'who_id' }
}
You can mark the uid in User as the id (primary key). That will make it automatically the foreign key in the Visitors domain.
class User {
String uid
static mapping = {
id column: 'uid'
}
...
Related
I have two domain classes: User and Book.
class Book implements Serializable{
String bookName
Timestamp createdDateTime
Blob file
static belongsTo = [User]
static hasMany = [user :User]
}
I am able to add user in book using addToUser() method.
But I am stuck in create criteria while applying filter in user.
def query = Book.createCriteria();
def results = query.list () {
eq("user",userObject) // not working since user field is a list of users.
order("createdDateTime", "desc")
}
Please help me with the correct way of filtering.
You need to join the user table first in a many-to-many relation. The criteria should look like:
Book.withCriteria {
user {
eq("id", userObject.id)
}
order("createdDateTime", "desc")
}
I'm not 100% sure how you're trying to model your domain but maybe you want a Book to have a single user? In which case you'd have the belongsTo relationship on Book e.g.
class Book {
String bookName
Timestamp createdDateTime
Blob file
static belongsTo = [user: User]
}
Then have the hasMany relationship on User e.g.
class User {
String name
static hasMany = [books: Book]
}
Then you can look Books up with criteria like:
def user = User.findByName( 'bob' )
def results = Book.createCriteria().list () {
eq( "user", user )
order( "createdDateTime", "desc" )
}
grails/gorm seems to ignore column names on join table on many to many relationship if one domain class has composite id, example:
class Following implements Serializable {
...
static hasMany = [operationTypes:OperationType]
static belongsTo = OperationType
static mappedBy = [operationTypes:'followings']
static mapping = {
...
id composite: ['offer', 'user']
offer column: 'offer_oid'
user column: 'user_oid'
operationTypes joinTable: [name: 'operationtype_following', key: ['favorite_user_offer_oid', 'favorite_user_user_oid']]
}
}
and:
class OperationType implements Serializable {
...
static hasMany = [offers:Offer, advices:Advice, followings:Following]
static mappedBy = [followings:'operationTypes']
static mapping = {
....
followings joinTable: [name: 'operationtype_following', key: 'operationtype_oid']
}
}
Results in:
MappingException: Foreign key (FK_lhri681gwbef5a9y6ylhoakpj:operationtype_following [favorite_user_offer_oid, favorite_user_user_oid,Following_offer_id,Following_user_id])) must have same number of columns as the referenced primary key (favorite_user [user_oid,offer_oid])
So why it not really ignores column names but adds generated column names to the specified ones?
Grails 2.4.3 is used. Any help appreciated
I was able to use a composite foreign key in a m:m relationship. this using the following mapping syntax. SITE and MACHINE_FK are the attributes of the join table.
static mapping = {
mstAttributeList {
column name: 'SITE'
column name: 'MACHINE_FK', sqlType: 'nvarchar2'
}
mstAttributeList joinTable: [name: 'MST_MACHINE_ATTRIBUTE', key: ['MACHINE_FK', 'SITE']]
}
static hasMany = [ mstAttributeList : com.gknsintermetals.mda.master.MstAttribute ]
My Grails app's domain model has the following requirements:
a user belong to zero or one organisations
an organisation is either a charity or a company
charities and companies have some some common fields and also some (non-nullable) fields that are unique to each organisation type
I put the common organisation fields into an abstract Organisation class which Charity and Company both extend. I can't store this hierarchy in a single table because there are non-nullable fields that are specific to each organisation type. The relevant parts of the domain model are shown below:
class User {
String name
static belongsTo = [organization: Organization]
static constraints = {
organization nullable: true
}
}
abstract class Organization {
String name
static hasMany = [users: User]
static mapping = {
tablePerHierarchy false
}
}
class Charity extends Organization {
// charity-specific fields go here
}
class Company extends Organization {
// company-specific fields go here
}
When I look at the MySQL schema generated from this model, the inheritance relationship between organisation-company and organisation-charity seems to have been completely ignored. Although there is an organisation table with a name column, it has no primary-foreign key relationship with either company or charity
I see the same result as IanRoberts for both MySQL and H2. In other words: no join table generated, but the expected organization_id FK in the users table.
With "Table per subclass" mapping (tablePerHierarchy false), you end up with an implied one-to-one relationship in the database. Primary Keys for Charity and Company will have the same value as the PK for the parent Organization. The schema generated by GORM/Hibernate3 doesn't appear to enforce this with referential integrity constraints. It's pure Hibernate magic. A bit more detail here
Solved!
Add the class below to src/java (this class cannot be written in Groovy)
package org.example;
import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsAnnotationConfiguration;
import org.hibernate.MappingException;
import org.hibernate.mapping.JoinedSubclass;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.RootClass;
import java.util.Iterator;
public class TablePerSubclassConfiguration extends GrailsAnnotationConfiguration {
private static final long serialVersionUID = 1;
private boolean alreadyProcessed = false;
#Override
protected void secondPassCompile() throws MappingException {
super.secondPassCompile();
if (alreadyProcessed) {
return;
}
for (PersistentClass persistentClass : classes.values()) {
if (persistentClass instanceof RootClass) {
RootClass rootClass = (RootClass) persistentClass;
if (rootClass.hasSubclasses()) {
Iterator subclasses = rootClass.getSubclassIterator();
while (subclasses.hasNext()) {
Object subclass = subclasses.next();
// This test ensures that foreign keys will only be created for subclasses that are
// mapped using "table per subclass"
if (subclass instanceof JoinedSubclass) {
JoinedSubclass joinedSubclass = (JoinedSubclass) subclass;
joinedSubclass.createForeignKey();
}
}
}
}
}
alreadyProcessed = true;
}
}
Then in DataSource.groovy set this as the configuration class
dataSource {
configClass = 'org.example.TablePerSubclassConfiguration'
pooled = true
driverClassName = "org.h2.Driver"
username = "sa"
password = ""
dbCreate = "update"
url = "jdbc:h2:mem:testDb;MVCC=TRUE;LOCK_TIMEOUT=10000"
}
I've submitted a pull request to Grails that fixes this. The fix was be included in Grails 2.3.9.
ORM is not RDBS.
tablePerHierarchy false
so You Have three tables: Organization, Charity, Company. User belongs to only Organization (not Charity or Company). How are you going to get value of specific fields?
There is USER. We know ORGANIZATION, but we don't know Charity or Company. I think you underst...
I can suggest you three solutions:
1. tablePerHierarchy true (But you need to have nullable charity\Company -specific fields )
2.
class User {
static belongsTo = [charity: Charity, company: Company]
}
class Charity {
String name
static hasMany = [users: User]
// charity-specific fields go here
}
class Company {
String name
static hasMany = [users: User]
// company-specific fields go here
}
3.
class User {
static belongsTo = [organization: Organization]
}
class Organization {
String name
Charity charity //nullable
Company company //nullable
static hasMany = [users: User]
}
class Charity {
static belongsTo = [organization: Organization]
// charity-specific fields go here
}
class Company {
static belongsTo = [organization: Organization]
// company-specific fields go here
}
Assume the user class:
class User {
String name
hasMany = [books: Book]
}
and the book class:
class Book {
String name
belongsTo = [user: User]
}
I want that the name of a book is unique per user. I.e., user1 can have books with name: [bookname1, bookname2] but he cannot have two books with the same name: [bookname1, bookname2]
User2 can also have books with name: [bookname1, bookname2] but not two books with the same name.
How can I restrict that the booknames are unique for each user?
Read the docs:
http://grails.org/doc/latest/ref/Constraints/unique.html
class Book {
String name
belongsTo = [user: User]
static constraints = {
name unique: 'user'
}
}
How would you model a friend - friendship relationship in Grails? Until now my User class had many followers
class User {
//Searchable plugin
static searchable = true
String userId
String password
boolean enabled = true
// For Spring Security plugin's user registration.
String email
String userRealName
boolean emailShow
Date dateCreated
Profile profile
static hasMany = [
posts : Post,
tags : Tag,
following : User,
authorities : Role,
notifications: Notification,
locations: Location,
incomingLocations:IncomingLocation,
]
static belongsTo = Role
static constraints = {
userId(blank: false, size:3..20, unique: true)
password(blank: false)
dateCreated()
profile(nullable: true)
userRealName(nullable: true, blank: true)
email(nullable: true, blank: true)
}
static mapping = {
profile lazy:false
}
}
But I would like to change the following:User for something like friendships:Friendship and create a Friendship class as following:
class Friendship {
static belongsTo= [user:User]
User friend2
boolean areFriends
}
Is this an ideal implementation?
How would you implement the handshake (accept/reject a pending friendship)?
You might not need to model Friendship directly. You can just have a hasMany relationship that relates the Users as friends. You don't create that relationship until someone accepts a FriendRequest. If they no longer want to be friends, then just remove the relationship between the 2 Users.
class User {
static hasMany = [friends:User]
}
class FriendRequest {
User fromUser
User toUser
}
That way Friendship doesn't have to do 2 things (relate users and track statuses). And friends becomes a natural object relationship which can make some things like optimizing fetching a bit easier.