I'm using tenant by schema and i have the following entities:
#Entity
#Multitenant(MultitenantType.TABLE_PER_TENANT)
#TenantTableDiscriminator(type = TenantTableDiscriminatorType.SCHEMA)
public class Person {
#OneToOne(mappedBy = "person", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private CTPS ctps;
}
#Entity
#Table(name = "CTPS")
#Multitenant(MultitenantType.TABLE_PER_TENANT)
#TenantTableDiscriminator(type = TenantTableDiscriminatorType.SCHEMA)
public class CTPS {
#OneToOne
#JoinTable(name = "PERSON_CTPS", joinColumns = #JoinColumn(name = "CTPS_ID"), inverseJoinColumns = #JoinColumn(name = "PERSON_ID"))
private Person person;
}
During an update at the same time using two differents tenants, occurs key violation error in one of requests, because tenant_a is trying to execute an insert in person_ctps table using tenant_b.
I'm using:
postgresql-9.4.5-3
wildfly-8.2.0
EclispeLink 2.6.3 with patchs of issues 410870 and 493235.
Anyone knows how to fix this?
I found the problem. The object that maintain relation tables is not cloned in EclipseLink.
With the attachment patch of issue 498891, the problem is solved
Related
I have a list with 25 MyApplication objects that I want to save using hibernate/JPA. This is done with the following method:
MyApplicationRepository.saveAll(myAppList);
However I noticed that hibernate creates over 60.000 MyApplication objects (close to the total amount of records already in database for this entity) while inserting/updating this list of 25 in the database. I don't have a lot of hibernate experience which leads me to believe I created a inefficient entity relations. A part of the MyApplication class:
public class MyApplication {
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "APPLICATION_CATEGORY", joinColumns = {
#JoinColumn(name = "applicationid", nullable = false, updatable = false) },
inverseJoinColumns = { #JoinColumn(name = "categoryid",
nullable = false, updatable = false) })
private Set<Category> categorySet;
#OneToMany(mappedBy = "myApplication",
cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<Screenshot> screenshotSet;
}
Category class (one example of multiple of the many to many relations of MyApplication):
public class Category {
#ManyToMany(fetch = FetchType.LAZY, mappedBy = "categorySet")
private Set<MyApplication> myApplicationSet;
}
Screenshot class:
public class Screenshot {
#ManyToOne
#JoinColumn(name = "applicationid")
private MyApplication myApplication;
}
What did I do wrong that resulted in Hibernate creating so many instances of MyApplication when saving?
Note 1: In the end all of the information of MyApplication and the information of it's categories and screenshots is saved correctly in the database.
Note 2: It's important that not only MyApplication is saved but also everything from all its categories and screenshots as well.
I was able to fix the issue. The problem was caused by the bidirectional nature of the manyToMany relation. This resulted in the category also querying all the applications from the database before saving. As this is not what I want, I resolved the issue by turning it into a unidirectional relation by removing the myApplicationSet from the Category class. Now only 25 MyApplication instances are constructed to save 25 applications and my memory usage remains stable.
Posting this here as I wasn't seeing much interest here: http://www.java-forums.org/jpa/96175-openjpa-one-many-within-one-many-merge-problems.html
Trying to figure out if this is a problem with OpenJPA or something I may be doing wrong...
I'm facing a problem when trying to use OpenJPA to update an Entity that contains a One to Many relationship to another Entity, that has a One to Many relationship to another. Here's a quick example of what I'm talking about:
#Entity
#Table(name = "school")
public class School {
#Column(name = "id")
protected Long id;
#Column(name = "name")
protected String name;
#OneToMany(mappedBy = "school", orphanRemoval = true, cascade = CascadeType.ALL)
protected Collection<ClassRoom> classRooms;
}
#Entity
#Table(name = "classroom")
public class ClassRoom {
#Column(name = "id")
protected Long id;
#Column(name = "room_number")
protected String roomNumber;
#ManyToOne
#JoinColumn(name = "school_id")
protected School school;
#OneToMany(mappedBy = "classRoom", orphanRemoval = true, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
protected Collection<Desk> desks;
}
#Entity
#Table(name = "desk")
public class Desk {
#Column(name = "id")
protected Long id;
#ManyToOne
#JoinColumn(name = "classroom_id")
protected ClassRoom classRoom;
}
In the SchoolService class, I have the following update method:
#Transactional
public void update(School school) {
em.merge(school);
}
I'm trying to remove a Class Room from the School. I remove it from the classRooms collection and call update. I'm noticing if the Class Room has no desks, there are no issues. But if the Class Room has desks, it throws a constraint error as it seems to try to delete the Class Room first, then the Desks. (There is a foreign key constraint for the classroom_id column)
Am I going about this the wrong way? Is there some setting I'm missing to get it to delete the interior "Desk" instances first before deleting the Class Room instance that was removed?
Any help would be appreciated. If you need any more info, please just let me know.
Thanks,
There are various bug reports around FK violations in OpenJPA when cascading remove operations to child entities:
The OpenJPA FAQ notes that the following:
http://openjpa.apache.org/faq.html#reorder
Can OpenJPA reorder SQL statements to satisfy database foreign key
constraints?
Yes. OpenJPA can reorder and/or batch the SQL statements using
different configurable strategies. The default strategy is capable of
reordering the SQL statements to satisfy foreign key constraints.
However ,you must tell OpenJPA to read the existing foreign key
information from the database schema:
It would seem you can force the correct ordering of the statements by either setting the following property in your OpenJPA config
<property name="openjpa.jdbc.SchemaFactory"> value="native(ForeignKeys=true)"/>
or by adding the org.apache.openjpa.persistence.jdbc.ForeignKey annotation to the mapping:
#OneToMany(mappedBy = "classRoom", orphanRemoval = true, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#org.apache.openjpa.persistence.jdbc.ForeignKey
protected Collection<Desk> desks;
See also:
https://issues.apache.org/jira/browse/OPENJPA-1936
My app has 2 java pojo classes linked via ManyToMany relationship User & Season:
#Entity
#Table(name = "user")
public class User implements Serializable {
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(name = "user_season", joinColumns = { #JoinColumn(name = "user_id") }, inverseJoinColumns = { #JoinColumn(name = "season_id") })
private Set<Season> followingSeason;
Set<Season> getSeasonsWhichTheUserFollows(){
return this.followingSeason;
}
}
Season class
#Entity
#Table(name = "season")
public class Season implements Serializable{
#ManyToMany(mappedBy = "followingSeason", fetch = FetchType.EAGER)
private Set<User> user;
}
When a user unfollows a season unfollowedSeason object I remove it from the set of season which the user follows.
Set<Season> seasonSet = user.getSeasonsWhichTheUserFollows();
seasonSet.remove(unfollowedSeason);
user.setFollowingSeason(seasonSet );
this.userService.update(user);
well this removes the entry from the user_season bridge table, everything is fine. But at the same time I also want to update some fields of the Season entity in the db for an instance decrementing the count of users following by 1. Is there a way I can do that within the same call? Or do I have to run a separate query to update the season entity?
Not sure if i got that right, but why can't you just put something in there like unfollowedSeason.setCount(unfollowedSeason.getCount() +1 ) and then just update the season?
EDIT AFTER DISCUSSION IN COMMENTS:
What you want to do is not possible because
you can't do a update and a remove in the same SQL Statement(as over9k stated)
I'm working on a java spring mvc application with hibernate. I have two Entities Acl and AclGroupand These two entities have Many to Many relationship with a join table. But, when I save an AclGroup object, hibernate doesn't insert any record in join table and just inserts into AclGroup table. Here is structure of my classes:
Acl.java:
public class Acl implements Serializable{
...
#JoinTable(name = "acl_group_acl", joinColumns = {
#JoinColumn(name = "acl_id", referencedColumnName = "id")}, inverseJoinColumns = {
#JoinColumn(name = "acl_group_id", referencedColumnName = "id")})
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Collection<AclGroup> aclGroupCollection;
public Collection<AclGroup> getAclGroupCollection() {
return aclGroupCollection;
}
public void setAclGroupCollection(Collection<AclGroup> aclGroupCollection) {
this.aclGroupCollection = aclGroupCollection;
}
...
}
AclGroup.java:
public class AclGroup implements Serializable{
...
#ManyToMany(mappedBy = "aclGroupCollection",fetch = FetchType.LAZY)
private Collection<Acl> aclCollection;
public Collection<Acl> getAclCollection() {
return aclCollection;
}
public void setAclCollection(Collection<Acl> aclCollection) {
this.aclCollection = aclCollection;
}
}
Here is how I save my object:
AclGroup aclGroup = new AclGroup();
List<Acl> acls = new ArrayList<>();
/*
add some elements to acls
*/
aclGroup.setAclCollection(acls);
/*
hibernate config and opening a session
*/
session.save(aclGroup); //session.persist also did not work
Could anyone help me to solve this problem? Thank you for your attention.
The owner side of the association is Acl. AclGroup is the inverse side (since it has the mappedBy attribute). Hibernate only cares about the owner side.
So make sure to add the group to the acl when you add the acl to the group: that will work whatever the owner side is, and will make your graph coherent. Or, if you absolutely don't want to do that, put the mapping annotations on AclGroup, and make Acl the inverse side.
This is more of a general 'understanding' question rather than a specific senario question.
I have been lookiing at the ways in which JPA maps tables together and found two examples here that seem to work in different ways.
One has a Set of Phone objects using #JoinTable to join STUDENT_PHONE to STUDENT by STUDENT_ID
The other has a Set of StockDailyRecord but seems to just use mappedby stock and in the stock_detail table object have the #PrimaryKeyJoinColumn annotation.
Simply trying to get an understanding of which method would be the prefered way and why?
Method 1:
#OneToMany(cascade = CascadeType.ALL)
#JoinTable(name = "STUDENT_PHONE", joinColumns = { #JoinColumn(name = "STUDENT_ID") }, inverseJoinColumns = { #JoinColumn(name = "PHONE_ID") })
public Set<Phone> getStudentPhoneNumbers() {
return this.studentPhoneNumbers;
}
Method 2:
#Table(name = "stock", catalog = "mkyongdb", uniqueConstraints = {
#UniqueConstraint(columnNames = "STOCK_NAME"),
#UniqueConstraint(columnNames = "STOCK_CODE") })
#OneToMany(fetch = FetchType.LAZY, mappedBy = "stock")
public Set<StockDailyRecord> getStockDailyRecords() {
return this.stockDailyRecords;
}
#Table(name = "stock_detail", catalog = "mkyongdb")
#OneToOne(fetch = FetchType.LAZY)
#PrimaryKeyJoinColumn
public Stock getStock() {
return this.stock;
}
Method #2:
It uses an extra column to build the OneToMany relation. This column is a Foreign key column of the other table. Before building the relation if these data needs to be added to the database then this foreign key column needs to be defined as nullable. This breaks the efficiency and cannot provide a normalized schema.
Method #1:
It uses a third table and is the efficient way to store data in a relational database and provides a normalized schema. So where possible its better to use this approach, if the data needs to be existed before building the relation.