My domain model includes several domain classes like so:
The Budget and Employee classes each know about a Position, but the Position class has no knowledge about the Budget or Employee classes. I would like to use GORM to do a query where I get back a list of Budgets and their associated Employees.
I have resorted to using HQL, since it doesn't look like there is a way to use a Criteria query across domains. My query looks like
from Budget as budget, Employee as employee where budget.position = employee.position
The problem with this query is that there is not a one-to-one mapping from Employees to Positions. That is, there can be Positions "floating" out there where no Employee is assigned to that Position. And a given floating position can be assigned to a Budget but not to an Employee.
I would like to use a left outer join in HQL, something like
from Budget as budget left outer join Employee as employee on employee.position = budget.position
But it looks like HQL only supports doing joins on properties that are directly on the domain classes. Neither Budget nor Employee knows about one another, so I'm not sure if this is possible. Is there a way to do the query I want in HQL?
Can you modify the domain class definition in grails for Position as such to let gorm know about the association?
Position {
static hasMany = [budgets:Budget, employees:Employee]
}
Then you can do and hql statment like such:
from Budget b left join b.position p where p.employees is not empty
Related
I'm new to Neo4J and I have a question about the most appropriate data model for a the problem domain described below.
Background
As I understand it, in Neo4J every relationship has a direction of sorts, outgoing, incoming or undirected. I read that a common mistake newbies make in "bi-directional" relationships is that they might model the relationship in both directions where in reality one undirected relationship would serve the purpose well. I also understand that irrespective of the direction it is possible at query time to ignore it and query based on either side of the relationship.
Problem Domain
This is a bit cliché, but stick with me, in a graph where "People" can connect with one another I felt tempted to model that as an undirected relationship. However, perhaps in my problem domain I want to store meta data on the relationship edge rather than at either of the People nodes. E.g. timestamp of when then connected or type of relationship (friend, family, employer etc...). Perhaps this is a "side effect" of using the spring-data-neo4j libraries but it seems that if I wish to data meta data on the edge rather than at the node I must create a class which is annotated as #RelationshipEntity rather than #NodeEntity. This necessitates a #StartNode and #EndNode which then seems to imply a direction to my otherwise undirected relationship...
Now, as it turns out this might not be a bad thing in my case because perhaps after all it turns out there is something useful about this additional directed context (e.g. perhaps I want to know who initiated the relationship so that the target node (person) must accept the invitation to be friends).
Now imagine that each person can place the "relationship" into a "group" like "friends, family, colleagues" etc I feel like I'd now need to actually have two distinct edges that point in either direction so that the meta data specific to the given direction has a natural place to reside. But this seems to have been described as a newbie anti-pattern.
Questions
I have two questions:
1) Should I use two separate distinct relationship edges that essentially point either way as a bi-directional relationship if I need to store meta data that is specific to the direction. e.g. Person A <--> Person B but person A placed Person B in the friends group whereas Person B placed A in the colleagues group.
2) Given the Java data model below, I am unclear what the direction attribute on the #Relationship annotation of Person should be. If I specify nothing it default to OUTGOING. But since it's a reflective relationship depending on which person instance you look at the relationship could be either outgoing or incoming, e.g. if person A adds person B, both are Person instances, but the direction is outgoing on the person A instance and incoming on the person B instance. Should the annotation be omitted altogether since I'm using a #RelationshipEntity?
Java Data Model
#NodeEntity
#EqualsAndHashCode(of = {"id"})
#NoArgsConstructor
public abstract class Person {
#GraphId
private Long id;
... other attributes
#Relationship(type = "CONNECTION_OF", direction = UNDIRECTED)
private Set<Connection> connections;
}
#Data
#RelationshipEntity(type = "CONNECTION_OF")
public class Connection {
#GraphId
private Long relationshipId;
... other meta-data
#StartNode
private Person from;
#EndNode
private Person to;
}
1) The rule of thumb that works well is to answer a question - if a relationship from A to B exists, can another relationship from B to A still be created, with different metadata? And can you delete one direction of the relationship independently of the other?
If the answer is yes they go for two directed relationships, otherwise stay with UNDIRECTED, and create initiatedBy=userId property or similar.
For your case where you put connections into groups - the thing is that you really categorize the people from another person's view, maybe it is a completely different fact independent of the CONNECTED_TO relationship?
You could e.g. create a group node and link that to owner and all people in the group, with following schema:
(:Person)-[:OWNS]-(:Group)-[:CATEGORIZED]-(:Person)
2) Keep the #Relationship(type = "CONNECTION_OF", direction = UNDIRECTED). For a given person X the connections Set is going to have elements that have from=X for outgoing edges mixed with elements that have to=X for incoming. All of these will be mixed in one collection.
From reading the docs in Grails I found the following statement:
However, excessive use of inheritance and table-per-subclass can
result in poor query performance due to the use of outer join queries.
In general our advice is if you're going to use inheritance, don't
abuse it and don't make your inheritance hierarchy too deep.
My question is: how deep is too deep?
Will 5 extensions in an inheritance chain make Grails cry?, 10?, 20?... what is the criteria to determine this?, or do we know if there is a clear way to extrapolate such performance degradation?
How deep is too deep? is a rather subjective question. But, it's possible to make an educated guess when you consider what happens at the database level with table-per-subclass inheritance. Lets assume you have these domain classes:
class Employee {
String firstName
String lastName
static constraints = {
}
static mapping = {
tablePerHierarchy false
}
}
class Supervisor extends Employee {
String office
static constraints = {
}
}
You'd end up with two tables: EMPLOYEE and SUPERVISOR. The EMPLOYEE table would contain the columns id, first_name, and last_name. But notice that the SUPERVISOR table would only contain the columns id and office.
This means that to retrieve a Supervisor GORM has to join both tables in order to populate the inherited properties.
SELECT EMPLOYEE.ID, FIRST_NAME, LAST_NAME, OFFICE
FROM SUPERVISOR INNER JOIN EMPLOYEE
ON SUPERVISOR.ID = EMPLOYEE.ID
It's these joins which have the potential to result in reduced performance. As you can imagine, 10 or 20 levels of inheritance would be disastrous. Yet a few, especially if the tables are small, would likely be OK.
Besides, a deep inheritance hierarchy is a sign that something is probably wrong with the domain model architecture (ie. consider using Traits).
You can read more about both forms of inheritance in my article here.
How can I make domain classes to make tables in Grails which 'share' data but do not 'belong' to the other? For example, I want to make 2 tables:
Person Table with 2 major columns
Name - Skills
Larry - Jumping, Laughing, Punching
Curly - Crying, Laughing
Moe - Punching, Dancing
Skill Table with 2 major columns
Name - Persons
Jumping - Larry
Crying - Curly
Laughing - Larry, Curly
Punching - Larry, Moe
Dancing - Moe
Deleting a Skill also removes that skill in the Person table, while deleting a Person also removes that person in the Skills table. I tried the domain class below, but when I generate views, I'm unable to enter multiple Skills per Person and vice versa.
class Skill {
String name
Person person
static hasMany = [person: Person]
class Person {
String name
Skill skill
static hasMany = [skill: Skill]
I've looked at other posts, but the solutions often have 3 or more classes (usually Book, Author, Chapter) and seem very complicated.
Thanks in advance
I think you need:
class Skill {
String name
}
class Person {
String name
static hasMany = [skills: Skill]
}
Grails will create a 3rd table called something like PERSON_SKILL which will have person_id and skill_id as columns. When editing what skills your person objects have, you are really editing records in this 3rd table.
Deleting a person record will delete all corresponding person_skill records for the person_id.
To delete a skill record, you'll need to manually delete all person_skill records for the skill_id first, before the skill record can be deleted.
Effectively, skill is acting as a static data table so doesn't need to belong to another domain object. I use several instances of this in my systems and Grails/GORM seems to automatically generate the obj1_by_obj2 link table for the ids.
I think your views/controllers/services can just deal with the person.skills collection (i.e. add, remove) then leave Grails to persist the updated collection to this 3rd table.
Give that a go.
I've two domain classes which are bonded with a bidirectional one-to-one relationship to each other, this being implemented using hasOne.
class AssessmentData {
static hasOne = [assessmentField:AssessmentField, assessment:Assessment]
AssessmentField field
}
class Assessment {
AssessmentData assessmentData
}
But I'm quite a bit confused about the way Grails implements this relationship at the database level. As described here, it simply sets the foreign key at the child domain class only, in my case, to the Assessment and AssessmentField tables. Its my primitive instinct that both tables should have a foreign key referring to each other in order to establish a one-to-one bidirectional relationship. But since this is not the case, I wanna know how this is achieved by Grails.
Its my primitive instinct that both tables should have a foreign key referring to each other in order to establish a one-to-one bidirectional relationship
Your instincts have failed you. The domain described in your question will generate these 2 database tables:
assessment_data
----------------
id
assessment
----------------
id
assessment_data_id
Using SQL we can get the assessment associated with an assessment_data with id 4
select * from assessment where assessment_data_id = 4
We can also go the other way and get the assessment_data associated with an assessment with id 5 using
select ad.* from assessment_data ad
inner join assessment a ON a.assessment_data_id = ad.id
where a.id = 5
So if we can "go both ways" in SQL, then we can do it with HQL, criteria queries, dynamic finders, etc. because these all ultimately get translated to SQL.
There is the possibility to disable the #OneToMany relationship join table with the #JoinColumn annotation. The default is a join table.
What are the advantages and disadvantages for a production system for example?
When should I use a join table and when not?
Thank you.
By default #OneToMany will create a join table only if you'll use unidirectional relationship.
In other words, if you have Employee and Project entities and the Employee entity is defined as follows (assume there is no orm.xml entries for these entities):
#Entity
public class Employee {
// ...
#OneToMany
Set<Project> projects;
}
#Entity
public class Project {
// ...
}
the JPA provider will create a join table (notice there is no mappedBy attribute in #OneToMany annotation as there is no reference to Employee entity from the Project).
On the other hand, if you'll use bidirectional relationship:
#Entity
public class Employee {
// ...
#OneToMany(mappedBy="employee")
Set<Project> projects;
}
#Entity
public class Project {
// ...
#ManyToOne
Employee employee;
}
The join table will not be used, as there "many" side will be used to store the foreign key for this relationship.
However, you can force to use join table even in cases when you have bidirectional #OneToMany relationship with defined mappedBy attribute. You can achieve it using #JoinTable annotation on the owning side of the relationship.
There is also a possibility, as you've mentioned, to use #JoinColumn in case where join table would be used by default (unidirectional #OneToMany relationship).
It's best to test the FK and join table performance difference for yourself. I can just guess that less joins (in this case: FK) seems to have better performance.
Moreover, sometimes the DBA defines the database schema and you just need to fit your mappings to the existing schema. Then you have no choice over FK or join table - that's why you have a choice.
Join tables are needed for polymorphisms. E.g., if Employee and Manager links the same project and they are mapped with one-table-per-class strategy, at the relational DB level, the only way to know that project( id = 1, emp_id = 10 ) refers to a manager is to put emp_id in the manager_2_employee table. If one is not in such a situation, then emp_id can go directly into project.
As mentioned in comments above, by default hibernate goes for join table.
This results in better db normalization.
If having a choice, JoinColumn gives better performance over the join table as need for the joining of an extra table in the SQL Query is removed.