I see there is a strategy for a one to one mapping for domain objects across different databases. But I am trying to associate two Domain objects that are in different datasources and have a one to many relationship.
class DomainA {
// default data source
}
class DomainB {
static hasmany = [domainA: DomainA]
static mapping = {
datasource 'ds2'
}
}
Any suggestions on how to make this work? Or a workaround?
Found a solution to this and it works pretty well. Solution is to create a join table in the schema you own.
E.g.
class DomainA {
// default data source
}
class DomainB {
List<DomainA> domainAList
static transients = ['domainAList']
static hasmany = [domainAIds: Integer]
static mapping = {
datasource 'ds2'
domainAIds joinTable: [name: 'DOMAINB_DOMAINA', key: 'DOMAINB_ID', column: 'DOMAINA_ID']
}
List<DomainA> getDomainAList(){
domainAList = domainAIds.collect { DomainA.get(it) }
domainAList
}
}
Related
I am using Grails 3.0.6 and am struggling with a complicated and highly interconnected domain model. I have classes with multiple many-to-many associations to other classes and I am left with no choice but to have multiple belongsTo associations on at least one class. I am unable to figure out the syntax to represent this.
My domain model was quite complicated, but I was able to reduce my problem to this simplified example:
class Graph {
static hasMany = [vertices: Vertex]
}
class OtherClass {
static hasMany = [vertices: Vertex]
}
class Vertex {
static hasMany = [graph: Graph, other: OtherClass]
}
In this simplified example, I could get around the problem by declaring the ownership between the domain classes on Graph and OtherClass... In my complicated domain model, I don't have this choice because there are too many classes with multiple many-to-many associations.
I have tried this:
class Vertex {
static hasMany = [graphs: Graph, others: OtherClass]
static belongsTo = Graph, OtherClass
}
but I get an NPE.
I have tried this:
class Vertex {
static hasMany = [graphs: Graph, others: OtherClass]
static belongsTo = [graphs: Graph, others: OtherClass]
}
but I still get "GrailsDomainException: No owner defined between domain classes [Graph] and [Vertex]"
Is there something I could do with mappedBy to correctly represent this?
In many of my many-to-many associations, cascading saves are not actually wanted (although they won't hurt), so I don't need belongsTo (or an "owner") for that purpose. This makes me wonder if associations on the domain classes are really how I should be modeling these relationships. Is there something else I could be doing?
per Burt Beckwith's comment, I created an additional domain class to represent the join table. Now, one many-to-many association is broken down into two one-to-many associations and the problem does not arise.
Example:
class Graph {
static hasMany = [graphVertexRelations: GraphVertexRelation]
}
class OtherClass {
static hasMany = [vertices: Vertex]
}
class Vertex {
static hasMany = [graphVertexRelations: GraphVertexRelation, others: OtherClass]
static belongsTo = OtherClass
}
class GraphVertexRelation {
static belongsTo = [graph: Graph, vertex: Vertex]
static GraphVertexRelation create(Graph graph, Vertex vertex, boolean flush = false) {
new GraphVertexRelation(graph: graph, vertex: vertex).save(flush: flush, insert: true)
}
}
The exception that you're seeing "GrailsDomainException: No owner defined between domain classes [Graph] and [Vertex]" means that the ORM can't figure out what the base class is, and there is a cyclical relationship between Graph and Vertex.
If you want to maintain the relationship to see what Graph a Vertex is in, you can do a backwards lookup using a criteria.
class Graph {
static hasMany = [vertices: Vertex]
}
class OtherClass {
static hasMany = [vertices: Vertex]
}
class Vertex {
static transients = ['graphs']
static hasMany = [other: OtherClass]
List<Graph> getGraphs() {
// Backwards link, using the graph table
Graph.withCriteria() {
vertices {
inList("id", [this.id.toLong()])
}
}
}
}
I am new to grails. I have the following requirement, how to achieve it ?
class File {
list<Employee> listOfCaseWorkersWhoHaveWorkedOnThisFile; <<<---- how to achieve this ?
static constraints = {
}
}
class Employee {
list<File> filesOwnedByHim <<<<<-------- also this ?
static constraints = {
}
}
My requirement is that a File will have a list of Employees with zero or more elements and same for Employee.
Do I have to implement one of the GORM (one-to-one, one-to-many etc) here ? If yes how ?
You can use hasMany which is one-to-many association between your classes.
class File {
static hasMany = [employees: Employee]
static constraints = {
}
}
class Employee {
static hasMany = [files: File]
static constraints = {
}
}
Then you can easily use GORM operations on it (addTo,findBy,etc).
Ref: http://grails.org/doc/latest/ref/Domain%20Classes/hasMany.html
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 read that a m:m relationship often means there is a third class that isn't yet required. So I have m:m on User and Project, and I created a third domain class, ProjectMembership
The three domains are as follows (minimized for illustration purposes):
User
class User {
String name
static hasMany = [projectMemberships : ProjectMembership]
}
Project Membership
class ProjectMembership {
static constraints = {
}
static belongsTo = [user:User, project:Project]
}
Project:
class Project {
String name
static hasMany = [projectMemberships : ProjectMembership]
static constraints = {
}
}
If I have the ID of the user, how can I get a list of Project objects that they are assigned to?
There are a handful of ways - here are a couple:
def user = User.get(userId)
ProjectMembership.findAllByUser(user).collect { it.project }
or to avoid the query for the User:
ProjectMembership.withCriteria {
user {
eq('id', userId)
}
}.collect { it.project }
Be wary of queries that'll return large result sets - you'll end up with a huge in-memory list of project objects.
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.