Even after reading the documentation, I seem to have a fundamental misunderstanding about Google App Engine's entity groups. My goal is a trivial example of ORM: I've got some Employees assigned to Departments. An employee can only be assigned to one department, but a department can have many employees. It's your standard one-to-many relationship.
Given the employee's key (email) and a department name, I want to look up both the employee and department objects, and if they don't exist, to create them.
What follows is pseudocode, not meant to compile. If producing code that will compile would help you help me, I'd be happy to do so, but I think my problem is conceptual.
Data Objects:
#Entity
public class Department {
private Key key;
private String name;
// getters and setters
}
#Entity
#NamedQuery(name="getEmployeesInDept", query="SELECT a from Employee a WHERE a.dept=:dept")
public class Employee {
private Key key;
private String firstName;
#ManyToOne
private Department dept;
// getters and setters
}
Look Up or Create
Key employeeKey = KeyFactory.createKey("Employee", email);
Employee employee = entityManager.find(Employee.class, employeeKey);
if(employee == null)
{
Key deptKey = KeyFactory.createKey("Department", deptName);
Department dept = entityManager.find(Department.class, deptKey);
if(dept == null)
{
dept = new Department();
dept.setKey(deptKey);
dept.setName(deptName);
entityManager.persist(dept);
}
employee = new Employee();
employee.setKey(employeeKey);
employee.setFirstName(firstName);
employee.setDept(dept);
entityManager.persist(employee);
}
entityManager.close();
print("Found employee " + employee.getFirstName() + " from " + dept.getName() + " department!");
That's the logic that worked perfectly when I was using ye olde generic ORM before I tried migrating to Google App Engine.
However, on GAE, I get an exception like:
javax.persistence.PersistenceException: Detected attempt to establish
Employee("bob#mycompany.com") as the parent of Department(14) but the
entity identified by Department(14) has already been persisted without
a parent. A parent cannot be established or changed once an object has
been persisted.
While I understand that in order to get Employee and Department into the same entity group (which I would prefer), I have to make one of them the parent of the other, their relationship isn't really one that fits into the parent-child paradigm in my mind.
I have tried wrapping various parts between entityManager.getTransaction().begin() and entityManager.getTransaction().end(), but to no avail.
I can get around this by including Department's key as part of Employee's key (thus making Department the parent of Employee), but then I have no idea how to look up an Employee based on their email and figure out what department they're in, or, conversely, how to look up all the employees in a given department.
Does this make sense? How should I structure this relationship in GAE? Surely this is a very common pattern that has a simple solution that is just eluding me.
I'm convinced that there's some fundamental piece of this puzzle that I'm missing, because it seems rather ridiculous that a simple many-to-one foreign key cannot be easily represented in GAE's ORM.
Cheers!
So if it doesn't fit owned relationships then make it unowned, which is supported in v2.x of the GAE JPA plugin.
Related
I have two database tables 'Student' and 'Course'. I want a one-to-one relation where there is foreign key of 'Course' table in 'Student' table. The foreign key 'course_id' is appearing in the Student table but whenever I try to save the Student data (after filling form), the data does not get saved and there is no error as well. I am very new to grails. Please guide me how I can save the data correctly.
The table structure is as desired but the data is not getting saved to the database. There is no issue with other code parts because the data is getting saved when I remove the association between the two tables.
Student controller
package com.grails
class studentController {
def save(Student student){
student.save()
}
}
Student domain class
class Student {
Course course
String firstName
String lastName
}
Course domain class
class Course{
String course_name
String duration
static hasOne = [student: Student]
//static belongsTo = [student: Student]
}
Note that grails 4 introduced a bug with one-to-one relationships that gives inconsistent behavior based on the owning side of the relationship: https://github.com/grails/grails-core/issues/11606
I'm not sure if this is the same problem you may be seeing without more information on your error, or even if you're on this version of grails.
I have the following class model:
I must make sure that an employee only has one role belonging to a project. So if Project A has the roles roleA and roleB, then the employee is only allowed to have one of them(but hes obviously allowed to have a role from another Project, but again, only one).
I make sure that thats always the case in my business logic. So before i add a role to an employee, i check whether the employee already has a role which belongs to the project of the role he wants to add, etc. So using my API/business logic, im able to make sure that the must criteria is fullfilled.
But should i add an extra layer of security on the database level? I could add triggers which check the above mentioned criteria. That would make it absolutely impossible to add any data into the database which violates my criteria. Is that extra layer of security on database level needed or is it enough if i do the validation in my business logic? And is a trigger the correct best way to do it?
Edit:
I implement what the comments suggested the following way:
My IdClass implementation:
#Data
public class TestId implements Serializable {
private Project project;
private Employee employee;
}
The class implementing the ternary association, making the employee and project pair unique:
#Entity
#Data
#IdClass(TestId.class)
public class Test {
#Id
#ManyToOne
private Project project;
#Id
#ManyToOne
private Employee employee;
#ManyToOne
private ProjectEmployeeRole projectEmployeeRole;
}
There are two questions in one.
Database: If you want the database to enforce this rule, you do not need any trigger. Just implement the many-to-many relation between Employee and Project using an association table with a primary key made of EmployeeId and the ProjectId: the combination must be unique. In the association table you'd also store the sole role this employee would have on that particular project.
UML class diagram: your diagram is misleading, since there are a lot of many-to-many association, but unfortunately, you say that one particular role can appear only in one project. A clearer way to represent this in UML would be to represent a ternary association (the association table I mentioned for the database would in fact impelment this ternary association). Another variant would be to use an UML association class and this association class could itself have an association with the role.
i'm struggling with gae for something that looks very simple to me.
let me explain.
i have a table with data about a person, i decided to use email as id
#Entity
public class Person{
#Id
#Column(name = "email")
String email;
...
what i would like to accomplish is
create a table with two columns, both containing email from Person, with the meaning "email in column 1 has written to email in column 2"
when i delete a row from Person, i would like that all the rows in the table at point 1 that contain this Person email in column 1 or 2 would be deleted as a cascade effect
i want to query my database so that, given an email address, i will be able to join all the rows in the table at point 1 and extract all the datas (name, phone...) of the Persons the given email has written to.
trouble is that apparently in gae i cannot use join, and i simply can't understand how to create a join table with cascade effect.
any help is welcome.
thanks in advance
Datastore isn't a relational database, so you should familiarise yourself with the concepts before starting to design a solution. What you're trying to do is fit a square peg into a round hole: not only will you find you're missing joins, you will also have to implement your own cascade-on-delete (hint: you may not want to do this but if you did, and you have a lot of data, look at Task Queues).
You don't provide much in the way of code, and I don't know JPA (tip: look at Objectify, it's much more suitable for the non-relational Datastore) but you might want something like this (using Objectify annotations):
#Entity
public class Person {
#Id
String email;
...
}
Then I'm assuming you will have some kind of Message entity (what you refer to as a two-column table):
#Entity
public class Message {
#Id
Long msgId;
#Index
Ref<Person> from;
#Index
Ref<Person> to;
...
}
Depending on what queries you need to perform, you may need to create a custom index (read here). Remember, queries on Datastore are index scans.
But, say, you want to get messages sent from Person A to Person B, you can do something like:
Person a = ofy().load().type(Person.class).id("a#example.com").now();
Person b = ofy().load().type(Person.class).id("b#example.com").now();
...
ofy().load().type(Person.class).filter("from =", Ref.create(a)).filter("to =", Ref.create(b)).list();
Instead of using Ref<Person> (essentially a Key), you could of course use a String representing the email. You may also not want to use email as the #Id as that would prevent a user changing their email address.
So if I have users and address tables. Because each users can buy or sell things so in the users table should have return_address, shipping_address, and billing_address. Then how can I define the relationship of these two tables?
Many-to-Many: because multiples users have multiple addresses (different type of address).
One-to-One: because each user only have one address.
One-to-Many: many users can share one address.
After reading some tutorials about hibernate, I find myself so confusing because now it has Many-to-One (I understand that it is a reversion of One-to-Many, but still confusing) .
Would any one mind to give me some advises and suggestions designing the database as well as optimization the database/query performance? It would be wonderful to help a new learner like me reduce the headache.
Thank you in advance.
User table will hold the address key.
#Entity
public class Customer{
#ManyToOne
#JoinColumn(name = "return_address_fk")
private Address returnAddress;
#ManyToOne
#JoinColumn(name = "shipping_address_fk")
private Address shippingAddress;
#ManyToOne
#JoinColumn(name = "billing_address_fk")
private Address billingAddress;
}
#Entity
public class Address{
// address properties
}
** Do not get confused.
Address should be a referred entity, means it's lifecycle does not depend upon User.
1.) Many users can have same returnAddress.
2.) Many users can have same shippingAddress.
3.) Many users can have same billingAddress.
If you say, One user can have Many returnAddress, shippingAddress, billingAddress, then add Many To Many annotation. Separate table will be created.
I have a Person class in Contacts subsystem. On the other hand in CRM subsystem, I have the notion of Customer.
In database design, I want to create a relationship between these notions. There are some possible ways:
Each customer is a person, thus customer should inherit from person and customer dies as soon as his person is removed (Composition). In this case, we create a one-to-one relationship between Id columns of the Customers table and People table, and we make the Id column of the People table an identity field, but we explicitly insert the scope_identity() in the Customers table.
Each customer has a person, thus customer and person have their own life-cycles (Aggregation) and can survive without the other. In this scenario, Customers table should have a foreign key to People table. The bad point here is that each Person can have many Customers which seems odd to me.
Which design is suggested as the best practice? I need solid objective answers. Thank you.
There are different cases when you may or may not give each table it's own ID.
In your case, it would be better if customer table does have it's own ID.
Example:
Own Id in a many to many relation defining table is redundant, when it doesn't have any extra column associated apart from the tables it is joining. Consider a Teacher and Student table relation. They have a many to many relation. If there is a table named TeacherStudentRelation having only foreign key to Teacher and Student table then it won't need any extra OwnId field.
But in your case, a Customer table surely would have extra information associated like balance, purchaseList or anything like that. And it is highly likely that you would search into Customer table for some data. Here an OwnId of customer table would let you to index that table.
Briefly, do give Customer table it's own Id.
IHMO, every entity must have a proper ID. You write about foreign key to refer Person as Customer, but this is another concept.
If Person is a base class about Customer, so, the ID field is the same and you don't explicit in Customer class because it inherit by Person.
In the first case (Person and Customer with FK) you have:
class Person {
private String id;
... and so on
... put here get and set property (as getId() / setId() and so on)
}
class Customer {
private String id; // this is different by id of Person class
private Person person;
... and so on
... put here get and set property (as getId() / setId() and so on)
}
In the second case (Customer extends Person) you have:
class Person {
private String id;
... and so on
... put here get and set property (as getId() / setId() and so on)
}
class Customer extends Person {
... other properties about Customer
... put here get and set property
}