Having the following kind of table tables. What will be the good approach to persist these tables? Used inheritance strategy for this, but it didn't work as expected.
Requirement 1: Need to persist student table, it will persist the member as well as address table as well
Requirement 2: Need to persist teacher table, it will persist the member as well as address table as well
Need to perform get, update and delete option on these tables.
Member {
member_id - have one to one relation with student id and teacher id
lastupdateddate
latupdatedby
}
Student {
student id - have one to one relation with member id
student name
lastupdateddate
latupdatedby
}
teacher {
teacher id - have one to one relation ship with member
teacher name
lastupdateddate
latupdatedby
}
address {
address id
member_id - have one to one relationship with member class
lastupdateddate
latupdatedby
}
When I persist/update student details, the address related info is not properly inserted or updated.When I check insert queries fired on member, then student table after on address table. But, in the insert query to address table, the member_id value is coming as null.Because of this only address table is not populated.
Entity structure is is as given below
public abstract class Member implements Serializable {
}
public class Student extends member implements Serializable {
}
public class Teacher extends member implements Serializable {
}
public class Address implements Serializable {
}
The mapping is mentioned as given below. Tried out various available options.
In member entity class
#Access(AccessType.PROPERTY)
#OneToOne(mappedBy="member", cascade=CascadeType.ALL)
public Address getAddress() {
return postalAddress;
}
In address entity class
#OneToOne(fetch=FetchType.LAZY)
#JoinColumn(name = "MEMBER_ID")
private Address address;
It looks like you have 2 options:
InheritanceType.JOINED. It's almost what you've described: common part is in one table, different parts are in different tables. On each request JOIN will occure
InheritanceType.SINGLE_TABLE. Here all the data will be stored in single table and descriminator will be used to determine if record if for student or for teacher.
Personally I would prefer second options because you have almost all fields in common, also most of operations are lighter and involve WHERE, not JOIN.
Related
I'm new in Grails. I have a problem with generation association many to one and one to many between two tables. I'm using postgresql database.
Employee.groovy
class Employee {
String firstName
String lastName
int hoursLimit
Contact contact
Account account
Unit unit
char isBoss
static hasMany = [positionTypes:PositionType, employeePlans: EmployeePlan]
}
EmployeePlan.groovy
class EmployeePlan {
AcademicYear academicYear
HourType hourType
int hours
float weightOfSubject
Employee employee
static belongsTo = [SubjectPlan]
}
I'd like to have access from employee to list of employeePlans and access from EmployeePlan to Employee instance. Unfortunately GORM generates only two tables Employee and EmployeePlan with employee_id. I don't have third table which should have two columns employee_id and employee_plan_id. Could you help me ?
I think your setup is correct, as you write from Employee class you can access to a collection of EmployeePlan (take care, that if you don't explicitly define EmployeePlan like a List, it will be a Set by default) and from EmployeePlan you can access Employee.
If you need List, you can define it like that:
class Employee {
String firstName
String lastName
int hoursLimit
Contact contact
Account account
Unit unit
char isBoss
//explicitly define List
List<EmployeePlan> employeePlans
static hasMany = [positionTypes:PositionType, employeePlans: EmployeePlan]
}
But back to your question. You'd like to have join table between Employee and employeePlan, but why? Its not necessary, since you have bidirectional mapping with sets (unordered), grails will not create a join table. Can you explain why do you need it? In grails the references will be auto-populated, so I don't see any issue here.
If need to preserve order of employeePlans, then define it as List, shown above, and grails will create a join table with corresponding indexes.
have you read the ref-doc? it gives you the answer immediately:
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']
}
}
BIG UPDATE:
Ok, I see my problem is much more complicated than I thought. I have tables like this:
Patient:
id
bloodtype
level (FK to level table)
doctor (FK to doctor table)
person (FK to person table)
Doctor:
id
person (FK)
speciality
level (FK to level)
Paramedic:
id
person (FK)
Person:
id
name
surname
Account:
id
login
pass
Level:
id
account (FK)
name (one of: 'patient' , 'paramedic' , 'doctor')
In entity class I'm using now #Inheritance(strategy= InheritanceType.JOINED)
#DiscriminatorColumn(discriminatorType=DiscriminatorType.STRING,name="name") in class Level. To check if someone is for ex. patient I have function:
public boolean ifPatient(String login) {
account = accountfacade.getByLogin(login);
for (Level l : account.getLevelCollection()) {
if (l instanceof Patient) {
return true;
}
}
return false;
}
Now I have situation: I'm logged in as a doctor. I want to add a patient. I have something like this:
public Doctor findDoctor(String login) {
account = accountfacade.getByLogin(login);
for (Doctor d : doctorfacade.findAll()) {
if (d.getLevel().getAccount().getLogin().equals(login)) {
doctor = d;
return doctor;
}
}
}
#Override
public void addPatient(Account acc, Patient pat, Person per, String login) {
Doctor d = findDoctor(login);
accountfacade.create(acc);
personfacade.create(per);
Patient p = new Patient();
p.setAccount(acc);
p.setBlood(pat.getBlood());
// etc
p.setPerson(per);
d.getPatientCollection().add(p);
acc.getLevelCollection().add(p);
}
But it doesn't work. Always totally weird errors like duplicate value of primary key in table Account (but I use TableGenerator...) or NULL value in field Account but for INSERT INTO Doctor (how?! I'm creating new Patient, NOT Doctor...). I'm totally lost now, so I think most important for me now is to know if actually I can use InheritanceType.JOINED in this case.
UPDATE:
You are using the field nazwa as discriminator
#DiscriminatorColumn(discriminatorType=DiscriminatorType.STRING,name="nazwa")
The framework stores there the name of the class that it has to use to deserialize the object (it is the name of the PoziomDostepu class).
As far as I can see you are using a different table for each class, so the Strategy.JOINED would make little sense.
More update:
Where I said class it meant entity. You can check the effect by changing the entity name (say to "CacaCuloPedoPis") of PoziomDostepu and seeing which is the new value being inserted.
Looks like all that is missing is a #DiscriminatorValue annotation on the PoziomDostepu class to use one of the values in your constraint, otherwise it defaults to the class name. The insert of PoziomDostepu is coming from the this.poziom - if you don't want PoziomDostepu instances inserted you might make the class abstract and make sure this instance is a subclass instead. You shouldn't need to change the inheritance type, as doing so will require changing the database tables to each contain the same fields.
Ok, I've done what I wanted. It's not elegant, but efficient. Tables and inheritance strategy are the same. In endpoint I create account and person entities, then I create Patient entity but using EntityManager persist() method. I also need to set id of level manually ((Integer)poziomfacade.getEntityManager().createQuery("SELECT max(p.idpoziom) FROM PoziomDostepu p").getSingleResult())+1 because Generator in Level entity class doesn't work. Nevertheless the problem is solved, thanks for every constructive comment or answer.
I am trying to design my ENTITY CLASSES using JPA annotations.
What I am trying to do is as follows :
A USER table with
id,
***email,
password,
activation_key,
active,
role***
and many TYPES OF USER table with for eg.
STUDENT_TABLE
USER_ID
FirstName
LastName
Company
Address
etc
MENTOR
USER_ID
FirstName
LastNAme
DOB
Department
etc
When USER will register depending o their ROLE they will be sotred in two tables (USER,MENTOR/STUDENT)
When they will log in , the ManagedBean will look into the UESR table to verify the authentication.
I tired to use #OneToOne but It just works with two tables.
I would really appreciate if any1 can help!!
Thanks
If I understand correctly, what you want is an inheritance relationship:
#Entity
#Inheritance(strategy = JOINED)
public abstract class User { ... }
#Entity
public class Student extends User { ... }
#Entity
public class Mentor extends User { ... }
The JOINED strategy tells JPA that the fields in the User class are stored in a table (USER), and that each subclass persists its own field in its own table (STUDENT and MENTOR), with a join column used to refer to the USER table ID.
I am learning JPA (2.0) and I would like to understand how to properly map multiple attributes of the same class type. For instance, pretend I have a model:
#Entity
class Person {
String name;
int age;
// getters/setters
}
#Entity
class Family {
Person dad;
Person mom;
List<Person> children;
// getters/setters
}
How can I properly map mom and dad attributes?
Thanks and sorry if it is too basic. Couldn't find an answer anywhere.
The fact that you have two instances doesn't change anything.
You map dad and mom each as a ManyToOne association, and there will be two join columns in the family table: one for dad and one for mom.
You map children as a OneToMany (assuming a child can only be a child in one family), and there will be either a join table between Family and Person (the default for a unidirectional OneToMany), or a join column in the Person table referencing the family table (the default for a OneToMany bidirectional association).
I have following table structure:
Table: Plant
PlantID: Primary Key
PlantName: String
Table: Party
PartyID: Primary Key
PartyName: String
PlantID: link to Plant table
Table: Customer
PartyID: Primary Key, link to Party
CustomerCode: String
I'd like to have Customer entity object with following fields:
PartyID: Primary Key
CustomerCode: String
PartyName: String
PlantName: String
I am having trouble with PlantName field (which is brought from Plant table
I connected Customer to Party and Party to Plant with associations
However I can not connect Customer to Plant with association ( because it does not have one)
I can not add Plant table to mapping, when I do that - I am getting following error:
Error 3024: Problem in Mapping Fragment starting at line 352: Must specify mapping for all key properties (CustomerSet.PartyID) of the EntitySet CustomerSet
Removing Plant association works.
Any hints or directions very appreciated.
You can get these fields by using the reference path on the Entity Object.
To get the PartyName, use this syntax: Customer.Party.PartyName
To get the PlantName, use this syntax: Customer.Party.Plant.PlantName
You can extend the Customer entity by using the public partial class:
public partial class Customer
{
public string PartyName
{
get { return Party.PartyName; }
set { Party.PartyName = value; }
}
public string PlantName
{
get { return Party.Plant.PlantName; }
set { Party.Plant.PlantName = value; }
}
}
After some research, I came across this thread on MSDN that says you can create a read-only entity, which is enough of a downside to not use it alone, but it gets worse. You will also lose the ability to update all of the models dynamically based on the schema of the database.