Jpa OneToMany with condition - jpa

I have 2 tables:
The first is "Persons":
person_id,
person_name
The second is "PersonsGraphs":
person_id1,
person_id2,
relation_type
I'm looking for a way to build a "family tree".
My first option is: load personGraphs into a HashTable and then recursively build the tree.
The second option I have come up with: use #OneToMany jpa-relation. This can work, but sometimes I have some relation_types that I want/don't want to include. Are there any options that would allow me to set some condition on the #OneToMany relation while using #JoinTable?
Thanks!
Oak

Try to use Hibernate #Where annotation, for example:
#Entity
public class Person {
#Id
#GeneratedValue
private Integer id;
private String name;
#Enumerated(EnumType.STRING)
private Gender gender;
#ManyToOne
private Person parent;
#Where(clause = "gender = 'MALE'")
#OneToMany(mappedBy = "person")
private List<Person> sons;
#Where(clause = "gender = 'FEMALE'")
#OneToMany(mappedBy = "person")
private List<Person> daughters;
}
public enum Gender {
MALE, FEMALE
}

I would recommend creating a Relationship class to model the join table.
Person - OneToMany - relations - Relationship - ManyToOne source - ManyToOne target
In EclipseLink you can add an Expression criteria to any relationship mapping,
http://wiki.eclipse.org/EclipseLink/Examples/JPA/MappingSelectionCriteria

Related

How to use multiple foreign keys in JPA?

I'm starting a project to know more in detail JPA.
Context:
At the end of his internship, the student has a report to make and a presentation in front of his professor to do about the internship.
I've a database, which is called "grade_management". It must contains a "student", "presentation", "report", "professor" and a "mark" (there are several rating criteria such as expression, quality of powerpoint ...) table. But now it's empty, since I want to make it throught JPA.
I've a "Presentation" class. Which countain this:
#Entity
public class Presentation implements Serializable {
#Id
#GeneratedValue (strategy=GenerationType.AUTO)
private int presentation_id;
private Date date;
private mark_id;
private int professor_id;
public Soutenance() {}
public Soutenance(Date date) {
this.date = date;
}
}
But the Presentation table contain 2 foreign key: professor_id and mark_id.
My question is: How can I indicate that both of them are foreign key ?
I'm sorry if I'm not clear, don't hesitation to ask question.
Cordially
You shouldn't reference other entities by their ID, but by a direct reference to the entity.
Something like that :
#ManyToOne
#JoinColumn(name = "mark_id", referencedColumnName = "id")
private Mark mark; // supposed here that mark_id if link to entity `Mark`
#ManyToOne
#JoinColumn(name = "professor_id", referencedColumnName = "id") // suppose "id" is the column name of the PK inside the table Professor.
private Professor professor; // supposed here that professor_id if link to entity `Professor`
This code is supposing that you use an unidirectional relation.
For bidirectional you have to define this in the other side (Mark/Professor type)
#OneToMany(mappedBy = "professor")
private Presentation presentation;
From your explanation, it looks like you have a Database named grade_management and in that database you have "student", "presentation", "report", "professor" and a "mark" tables (i.e: which are #Entity by themselves defined in their separate respective classes )
I'm not sure whether you have defined them or not. If not then you have to define them first and then use the refactored code mentioned below.
So, you will have many-to-one relation mapping. You can annotate your foreign keys belonging to different tables using #ManyToOne annotation to indicate relation type and #JoinColumn annotation to indicate that this entity has a foreign key to the referenced table.
You can redefine your Presentation class show below:
#Entity
#Table(name = "Presentation")
public class Presentation implements Serializable {
#Id
#Column(name="presentation_id")
#GeneratedValue (strategy=GenerationType.AUTO)
private int presentation_id;
private Date date;
#ManyToOne
#JoinColumn(name = "mark_id")
private Mark mark_id;
#ManyToOne
#JoinColumn(name = "professor_id")
private Professor professor_id;
public Soutenance() {}
public Soutenance(Date date) {
this.date = date;
}
//getter and setter
}
Also, if you need more information to read upon for yourself you can always checkout this Hibernate Documentation that explains everything you'll need to know.

Model Look up table for a JPA Entity Field

I'm trying to find out the appropriate relationship to be used in order to model an JPA Entity Field which needs a Look-up table (Comboxbox equivalent on the UI) to select the value from. An example below:
#Entity
public class Employee {
#Id
private int employeeId;
private String name;
private Department department;
}
#Entity
public class Department {
#Id
private int id;
private String name;
}
The instances of Department could be as follows:
Id | Name
-----------------------
100 | Human Resources
101 | Sales
102 | Finances
For an employee, the department field should get a value from one of the above. What should be the JPA annotations for the corresponding fields in both the entities?
Thanks,
Sandeep Joseph
I think you are looking for a unidirectional ManyToOne relationship from Employee to Department, something like this:
#Entity
public class Employee {
#Id
private int employeeId;
private String name;
#ManyToOne
#JoinColumn(name = "department_id", nullable = false)
private Department department;
}
This means an employee must be associated to a single department and a department can be associated to many employees.
If you need to know the list of employees associated to a department then you can make the relationship bidirectional by adding this:
#Entity
public class Department {
#Id
private int id;
private String name;
#OneToMany(mappedBy = "department")
private Collection<Employee> employees;
}

How to disable delete for JoinTable?

I have problem with disable delete for JoinTable.
#Entity
class Employee
{
#Id
Long id;
#ManyToOne( cascade = { CascadeType.REFRESH } )
#JoinTable( name = "Employee2AddressOracleView",
joinColumns = #JoinColumn( name = "employee_id" ),
inverseJoinColumns = #JoinColumn( name = "address_id" )
private Address address;
)
Address for Employee is calculated in View. It works, I can load Employee but when I want delete employee JPA want delete row from view to. It is possible to disable this delete query?
JPA query in console:
delete from Employee where employee_id = ?
delete from Employee2AddressOracleView where employee_id = ?
The accepted answer has a link to hibernate forums which are dead. I managed to pull the link out on archive.org.
The solution is to create a separate entity representing the join table, mapped to the view, instead of using #JoinTable.
Main entity mappings:
#Entity
#Table(name="Main")
public class MainEntity {
#Id
#Column(name="id")
private Integer id;
#OneToOne
#PrimaryKeyJoinColumn
private JoinTableViewEntity joinEntity;
}
Join table view entity mappings:
#Entity
#Table(name="TableView")
public class JoinTableViewEntity {
#Id
#Column(name="id")
private Integer mainEntityId;
#ManyToOne
#JoinColumn(name="other_id", updatable=false, insertable=false)
private OtherEntity other;
}
It also works without updateable and insertable attributes.
If you are using EclipseLink you can use a DescriptorCustomizer to make the mapping readOnly.

efficient JPQL: update entities in #onetomany

i have two entities Customer and Order (trivial setters and getters excluded)
#Entity
public class Customer {
#GeneratedValue
#Id
private int id;
#OneToMany
List<Order> orderList;
}
#Entity
public class Order {
#GeneratedValue
#Id
private int id;
#ManyToOne
Customer customer;
private boolean paid;
public Order(Customer customer) {
this.customer = customer;
customer.getOrderList().add(this)
}
}
Now i want to set 'paid = true' for all the orders of a given customer
Below query seem to do the trick, but I get a feeling it is innefficient and the fact that i stored the reverse relationship in Customer.orderList hints that there should be some other way to do this.
UPDATE Order o SET o.paid = true WHERE EXISTS
(SELECT c.orderList FROM Customer c WHERE o MEMBER OF c.orderList AND c = :customer)
I'm using container managed transactions, glassfish and javaDb. But I'd prefer if improvements could be done in JPA/JPQL domain and not specific to container or db.
private id; ?? missed field type
Add to #OneToMany annotation,cascade = CascadeType.All
Customer entity = entityManager.find(Customer.class, id)
for (Order order : entity.getOrderList())
{
order.setPaid(true);
}
if you are using cantainer managed transaction then true will be saved to DB

JPA Query Many To One nullable relationship

I have the following entities and would like to seek help on how to query for selected attributes from both side of the relationship. Here is my model. Assume all tables are properly created in the db. JPA provider I am using is Hibernate.
#Entity
public class Book{
#Id
private long id;
#Column(nullable = false)
private String ISBNCode;
#ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY, optional = false)
private Person<Author> author;
#ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY, optional = true)
private Person<Borrower> borrower;
}
#Inheritance
#DiscriminatorColumn(name = "personType")
public abstract class Person<T>{
#Id
private long id;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Info information;
}
#Entity
#DiscriminatorValue(PersonType.Author)
public class Author extends Person<Author> {
private long copiesSold;
}
#Entity
#DiscriminatorValue(PersonType.Borrower)
public class Borrower extends Person<Borrower> {
.....
}
#Entity
public class Info {
#Id
private long id;
#Column(nullable=false)
private String firstName;
#Column(nullable=false)
private String lastName;
......;
}
As you can see, the book table has a many to one relation to Person that is not nullable and Person that is nullable.
I have a requirement to show, the following in a tabular format -
ISBNCode - First Name - Last Name - Person Type
How can I write a JPA query that will allow me to select only attributes that I would want. I would want to get the attributes ISBN Code from Book, and then first and last names from the Info object that is related to Person Object that in turn is related to the Book object. I would not want to get all information from Info object, interested only selected information e.g first and last name in this case.
Please note that the relation between the Borrower and Book is marked with optional=true, meaning there may be a book that may not have been yet borrowed by someone (obviously it has an author).
Example to search for books by the author "Marc":
Criteria JPA Standard
CriteriaQuery<Book> criteria = builder.createQuery( Book.class );
Root<Book> personRoot = criteria.from( Book.class );
Predicate predicate = builder.conjunction();
List<Expression<Boolean>> expressions = predicate.getExpressions();
Path<Object> firtsName = personRoot.get("author").get("information").get("firstName");
expressions.add(builder.equal(firtsName, "Marc"));
criteria.where( predicate );
criteria.select(personRoot);
List<Book> books = em.createQuery( criteria ).getResultList();
Criteria JPA Hibernate
List<Book> books = (List<Book>)sess.createCriteria(Book.class).add( Restrictions.eq("author.information.firstName", "Marc") ).list();
We recommend using hibernate criterias for convenience and possibilities.
Regards,