I have situation that the same table is linked two different keys
all names either it manager's name or name of the employee stored in "employee_table" reason is manager is also an employee
manager_link_table
id
manager_id
employee_table
id
name
Now I want two child objects as below
I am trying to create JPA Entity with OneToOne as
#Entity
#Table(name="manager_link_table")
class ManagerLinkTable {
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn( name="id", referencedColumnName="id")
private EmployeeTable employee;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn( name="id", referencedColumnName="manager_id")
private EmployeeTable manager;
}
#Entity
#Table(name="employee_table")
class EmployeeTable {
private String id;
private String name;
}
I am writing JPA query as
SELECT m FROM ManagerLinkTable m
I want m.employee.name and m.manager.name to be different
But I am getting the same, it seems the referencedColumnName is ignored while joining the table
Does anyone faced this issue ?
Related
I have faced with issue trying to select for update row using Spring data with Hibernate as JPA implementation and Postgresql.
Suppose we have entities:A,B,C.
public class A{
#Id
private Long id;
#OneToMany(fetch = FetchType.EAGER)
private Set<B> bSet;
#OneToMany(fetch = FetchType.EAGER)
private Set<C> cSet;
}
Suppose we want to select A with all related B and C entities for update i.e. with locking row related to A table.
#Query(SELECT a FROM A a
LEFT JOIN FETCH a.bSet
LEFT JOIN FETCH a.cSet
WHERE a.id=?)
#Lock(LockModeType.PESSIMISTIC_WRITE)
public A selectAndLockA(Long Aid);
The query will look like
SELECT a.column1, ... from tableA a LEFT JOIN tableB b ... FOR UPDATE of a,c
FOR UPDATE of a,c
The query will try to lock two tables what leads to exception like :
org.postgresql.util.PSQLException: ERROR: FOR UPDATE cannot be applied to the nullable side of an outer join
What I try to archive is locking only first table "FOR UPDATE OF a"
Is it possible to configure somehow or tell Hibernate to lock only first table.
This is not supported by PostreSQL. If you do an outer SELECT nothing can prevent somebody from inserting a row into the LEFT JOINED table thereby modifiying the result set you are looking at (e.g. the columns would not be NULL anymore on a repeated read).
For a detailed explanantion see here
It's been a long time since question was created, but I have a similar problem and hope my answer will help somebody.
Suppose that we have this JPA entities:
#Entity
#Table(name = "card_transactions")
public class CardTransactionsEntity {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "card_trans_seq")
#SequenceGenerator(name = "card_trans_seq", sequenceName = "card_trans_seq")
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumns({
#JoinColumn(name = "ofd_id", referencedColumnName = "ofd_id"),
#JoinColumn(name = "receipt_id", referencedColumnName = "receipt_id")})
private ReceiptsEntity receipt;
#Column
#Enumerated(EnumType.STRING)
private CardTransactionStatus requestStatus;
...
}
#Entity
#Table(name = "receipts")
public class ReceiptsEntity {
#EmbeddedId
private OfdReceiptId id;
...
}
#Embeddable
public class OfdReceiptId implements Serializable {
#Column(name = "ofd_id")
#Enumerated(EnumType.STRING)
private OfdId ofdId;
#Column(name = "receipt_id")
private String receiptId;
...
}
And we want select CardTransactionsEntity with fetched ReceiptsEntity for pessimistic update only CardTransactionsEntity. This can be done using Hibernate and Spring Data JPA repository as
public interface CardTransactionRepository extends JpaRepository<CardTransactionsEntity, Long> {
#Query("select ct from CardTransactionsEntity ct left join fetch ct.receipt r where ct.requestStatus = :requestStatus")
#Lock(value = LockModeType.PESSIMISTIC_WRITE)
#QueryHints(value = {
#QueryHint(name = "javax.persistence.lock.timeout", value = "-2"), // LockOptions.SKIP_LOCKED
#QueryHint(name = "org.hibernate.lockMode.r", value = "NONE") // "r" is alias for ct.receipt and will excluded from PESSIMISTIC_WRITE
})
List<CardTransactionsEntity> loadCardTransactions(#Param("requestStatus") CardTransactionStatus requestStatus, Pageable pageable);
}
This repository method will execute query like
SELECT ct.*, r.* from card_transactions ct LEFT OUTER JOIN receipts r ON ct.ofd_id = r.ofd_id and ct.receipt_id = r.receipt_id WHERE ct.request_status=? LIMIT ? FOR UPDATE OF ct SKIP LOCKED
You can bypass this error with joining the tables with FetchType.LAZY. This fetch type is the default one and it is not required to specify for #OneToMany joins.
public class A{
#Id
private Long id;
#OneToMany
private Set<B> bSet;
#OneToMany
private Set<C> cSet;
}
Parent Table:
#Table(name="parent_table_t")
public class ParentTable implements Serializable {
#Id
#Column(name="contact_id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer contactId;
---------
---------
#OneToOne (cascade = CascadeType.ALL, mappedBy = "parentTable")
private ChildTable childTable;
}
Child Table:
#Table(name="child_table_t")
public class ChildTable implements Serializable {
#Id
#Column(name="child_id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer childId;
#Column(name="contact_id")
private Integer contactId;
#JoinColumn(name="contact_id", referencedColumnName = "contact_id", insertable=false, updatable=false)
#OneToOne(cascade = CascadeType.ALL)
private ParentTable parentTable;
}
My requirement is when contact_id is generated in Parent_table_t, it should be copied into contact_id of child_table_t when saved.
When I am calling saveAndFlush / save on Parent Table Entity, it is:
Generating the auto-increment for Parent->contact_id.
But Child_table_t -> contact_id is always null.
Can someone please help in this.
I am using in-memorty hsqldb with spring-boot and JPA.
You marked the relationship #JoinColumn with insertable=false, updatable=false, likely because you have an integer mapping for the column as well. Unfortunately, these settings prevent JPA from setting it with values from the relationship, which instead is forced to set the column with the value in the contactId attribute.
Put the insertable=false, updatable=false on the #Column instead.
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.
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
I have a JPA entity with a list of child entities. In this case a user entity with roles attached to it.
It looks (a bit simplified - some fields/methods omitted) like this:
#Entity
public class MyUser{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long myUserId;
private String username;
#OneToMany
#JoinTable(name = "userrole",
joinColumns = {
#JoinColumn(name="myUserId", unique = true)
},
inverseJoinColumns = {
#JoinColumn(name="roleId")
}
)
private Collection<Role> roles;
public Collection<Role> getRoles() {
return roles;
}
}
If intressting, the Role entity is very simple.
#Entity
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long roleId;
private String role; // a few more string fields here .
When I add two users and a few hundred roles per user I get a wierd behaviour when I list the users. Each user get's listed a few hundred times (same user = same unique id).
The problematic code:
Query q = em.createQuery("SELECT u FROM MyUser u LEFT JOIN FETCH u.roles");
Collection<MyUser> users = q.getResultList();
for(MyUser u : users){
// print/use u here
}
However, when I just access the database and do select statements, it seems fine. Every user exists only once.
I use OpenJPA 1.2 together with a IBM DB2 database in this case.
I think you have your model wrong, typically a user-role relationship is not OneToMany but "ManyToMany" so you should change your code to look something like this:
#Entity
public class MyUser{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long myUserId;
private String username;
#ManyToMany //This should be many to many
#JoinTable(name = "userrole",
joinColumns = {
#JoinColumn(name="myUserId") //The userId in the join table should
//NOT be unique because the userId can
//be many times with different roles
},
inverseJoinColumns = {
#JoinColumn(name="roleId")
}
)
private Collection<Role> roles;
public Collection<Role> getRoles() {
return roles;
}
}
Try this way and see if it works.
Also your query shouldn't need the Left Join, the roles should be fetched automatically by JPA once you use the getRoles() method on each entity (using LAZY Fetch)
Actually, it's reasonable to have #ManyToMany mapping for User and UserRole entities. The problem with your query is that it returns all the rows from the join table what I believe you don't need. So just add group by u to your query as follows:
SELECT u FROM MyUser u LEFT JOIN FETCH u.roles GROUP BY u
and you'll be done.