Hibernate delete all objects associations that reference the object unidirectional using ManyToOne - java

I have a ModuleData object and a Setting object that references this ModuleData object, but the ModuleData object does not have any reference to the Setting object. Does Hibernate automatically delete the objects that reference ModuleData and if not, how do I accomplish that Hibernate does this.
ModuleData.java
#Entity
#Table(name = "modules")
public class ModuleData {
#Id
#GeneratedValue
#Column(name = "id", updatable = false, nullable = false)
private long id;
#Column(name = "name")
private String name;
#Column(name = "version")
private String version;
}
Setting.java
#Entity
#Table(name = "settings", uniqueConstraints = #UniqueConstraint(columnNames = {"settingKey"}))
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Setting {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "settingKey", nullable = false)
private String key;
#Column
private String value;
#ManyToOne
#JoinColumn(name = "moduleId", nullable = false)
private ModuleData module;
I will delete by session.delete(moduleData).

You can add the other side of the relation (i.e. add the Setting property to the ModuleData class), and then use Java Persistence 'cascade types' to accomplish this. Specifically the CascadeType.REMOVE will give you the desired behavior. From this great tutorial, your ModuleData class would reference its Setting child similar to this:
#OneToMany(cascade = CascadeType.ALL, mappedBy = "post", orphanRemoval = true)
private List<Comment> comments = new ArrayList<>();
so it would look something like:
#OneToMany(cascade = CascadeType.REMOVE, orphanRemoval = true, ...)
private List<Setting> settings;
Another great tutorial on cascade types:
https://www.baeldung.com/jpa-cascade-types

Related

HIbernate ignore fetching data from OnetoMany field

I would like to ignore #OnetoMany field in my entity. fetch data need to get actual fields but don't want to fire query to dependent table. But deleting data from parent table needs deletion from dependent table
I have tried #Transient that ignores but the delete is also being ignored. Is there any other option to tell JPA not to fetch data from childs table when i call the parent entity?
#Entity
Table(name = "User")
public class UserEntity implements Serializable {
#Id
#Column(name = "id")
private int id;
#Column(name = "SERIAL", unique = true, nullable = false)
private String serial;
#OneToMany(mappedBy = "serialBySerialId", cascade = CascadeType.ALL)
private Set<UserActionEntity> userActionsById;
}
#Table(name = "user_action")
public class UserActionEntity implements Serializable {
#Id
#Column(name = "id")
private int id;
#Column(name = "action")
private String action;
#ManyToOne
#JoinColumn(name = "USER_ID", referencedColumnName = "ID", nullable = false)
private UserEntity userByUserId;
If you don't want to fire query to dependent table, you can use (fetch = FetchType.LAZY) on UserActionEntity property.
#OneToMany(mappedBy = "serialBySerialId", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<UserActionEntity> userActionsById;

Hibernate unexpected deletes when finding entities

We have a Java ee application running on JBoss 6.4 GA using JPA and Hibernate with the following entities:
#Entity
#SequenceGenerator(name = "sequence", sequenceName="SEQ_CAMPAIGNS_ID",allocationSize = 1)
#Table(name = "CAMPAIGN")
public class CampaignEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence")
#Column(name = "ID")
private Long id;
#Column(name = "NAME")
private String name;
#Column(name = "IS_ACTIVE", nullable = false)
private boolean active;
#Column(name = "START_DATE", nullable = false)
private Date startDate;
#Column(name = "END_DATE", nullable = false)
private Date endDate;
#Column(name = "LEGAL_ENTITY_ID", nullable = false)
private Integer legalEntityId;
#Column(name = "DEPARTMENT", nullable = false)
#Enumerated(value = EnumType.STRING)
private Department department;
#Column(name = "CATEGORY", nullable = false)
#Enumerated(value = EnumType.STRING)
private Category category;
#Embedded
CampaignConditionsEntity campaignConditions;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "campaign", orphanRemoval = true)
#OrderBy
private List<CodeEntity> campaignCodes;
public CampaignEntity() {
}
And the following CampaignConditionsEntity:
#Embeddable
public class CampaignConditionsEntity implements Serializable {
private static final String CAMPAIGN_ID = "CAMPAIGN_ID";
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "CAMPAIGN_COND_TRIP_TYPE", joinColumns = #JoinColumn(name = CAMPAIGN_ID))
private Set<TripTypeConditionEntity> tripTypeConditions;
And the following CodeEntity:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
#SequenceGenerator(name = "sequence", sequenceName = "SEQ_CODES_ID", allocationSize = 1)
public abstract class CodeEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence")
#Column(name = "ID", nullable = false)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "CAMPAIGN_ID")
private CampaignEntity campaign;
#OneToOne(mappedBy = "code", cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false, orphanRemoval = true)
private DiscountEntity discount;
#Column(name = "MAX_USAGES", nullable = false)
private Integer maxUsages;
#Column(name = "UNLIMITED_USAGES", nullable = false)
private boolean unlimitedUsages;
#Column(name = "NEGATIVE_SH", nullable = false)
private boolean negativeSH;
#Column(name = "UNIQUE_BUYER", nullable = false)
private boolean uniqueBuyer;
#Column(name = "START_DATE")
private Date startDate;
#Column(name = "END_DATE")
private Date endDate;
#Embedded
private CodeConditionsEntity codeConditions;
public CodeEntity() {
}
This is the CodeConditionsEntity:
#Embeddable
public class CodeConditionsEntity implements Serializable {
private static final String CODE_ID = "CODE_ID";
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "CODE_COND_TRIP_TYPE", joinColumns = #JoinColumn(name = CODE_ID))
private Set<TripTypeConditionEntity> tripTypeConditions;
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "CODE_COND_CARRIERS", joinColumns = #JoinColumn(name = CODE_ID))
private Set<CarrierConditionEntity> carrierConditions;
This is the CarrierConditionEntity:
#Embeddable
public class CarrierConditionEntity implements Serializable {
#Column(name = "CARRIER", nullable = false, length = 3)
private String carrierCode;
#Column(name = "IS_INCLUDED", nullable = false)
private boolean included;
The problem is that in the logs we are finding unexpected deletes when the only operation that we are doing are finds of particular campaign entities.
In the production logs we find the following deletes
Hibernate: delete from CODE_COND_CARRIERS where CODE_ID=? and CARRIER=? and IS_INCLUDED=?
do you have any suggestion?
thanks
I have some suggestions :)
Be aware of what is a Persistence Context (EntityManager instance in JPA terminology / Session in Hibernate one), the entity lifecycle and transaction scope (unit of work)
Do not mutate entity state if you don't expect the changes to be reflected in database, or at least detach the entity before mutating it.
Mark your transaction as "readOnly" if you only fetch data in the related unit of work. (beware that if you have many "Transactional" methods joining the same physical transaction, the flag is set by the surrounding one and cannot be overridden by inner logical transactions). That way the EntityManager won't be flushed at the end of the transaction and pending changes won't be persisted to the database.
You can track the method triggering the unexpected deletion using an EntityListener on the related entity and printing the current strackTrace (new Throwable().printStackTrace()/ log(new Throwable()) in the PreRemove method
I found where was the problem:
The problem was that the Entities didn't have the equals() and the hashcode() implemented. Also there were entities that have a #PostLoad that modified the entity after loading it from database. Then in this situation Hibernate though that there was a change in those entities that didn't have the equals and the hashcode, and then it delete all of them and inserted again in the database (to have the same entities before the query)
Adding the equals and hashcode methods and deleting postload removed the unexpected deletes and inserts from the logs.
regards

JPA: OneToMany relationship with multiple mappedBy attributes

I'm having a problem to map a relationship between instances of one single entity. Let me give you the JPA entities first.
Article entity
#Entity
#Table(name = "article")
public class Article {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "article", orphanRemoval = true)
private Collection<Keyword> keywords;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "article1", orphanRemoval = true)
private Collection<RelatedArticles> relatedArticles;
#Column(name = "content", nullable = false)
#Lob
private String content;
...
}
RelatedArticle entity
#Entity
#Table(name = "related_articles")
public class RelatedArticles {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#JoinColumn(name = "article1_id")
#ManyToOne(optional = false)
private Article article1;
#JoinColumn(name = "article2_id")
#ManyToOne(optional = false)
private Article article2;
private Float weightedJaccardIndex;
...
}
Further explanation
An article can be related to other articles which is realized by the RelatedArticle entity. The article can be referenced by article1 or article2. That means the collection relatedArticles in Article should contain all instances of RelatedArticle where the ID either matches article1 or article2.
Question
How can I map a single collection of RelatedArticles in my Article entity where the origin Article is either article1 or article2?
Alternative solutions are welcome!

Inheritance in JPA not working

I have a parent class:
#MappedSuperclass
public class BaseText implements Serializable {
#Column(name = "LOCALE_CODE", nullable = false)
private String localeCode;
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#Index
#Column(name = "LOCALIZED_TEXT_ID", nullable = false)
#ForeignKey
private LocalizedText localizedText;
//getters and setters
}
And one of the sub classes:
#Entity
#Table(name = "ASSESSMENT_TEXT")
#AttributeOverride(name = "localeCode", column = #Column(name = "LOCALE_CODE"))
#AssociationOverride(name = "localizedText", joinColumns = #JoinColumn(name = "LOCALIZED_TEXT_ID"))
public class AssessmentText extends BaseText {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private Long id;
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#Index
#Column(name = "ASSESSMENT_ID", nullable = false)
#ForeignKey
private Assessment assessment;
//Getters and setters.
}
When I am trying to persist an object I get the following error:
org.apache.openjpa.persistence.ArgumentException: Superclass field "java.lang.Object.localizedText" is mapped in the metadata for subclass "com.my.com.AssessmentText", but is not a persistent field.
What is causing this and how to solve it?
I am using embedded derby database in JUnit and the JPA implementation is OpenJPA.
I am not sure that it is the solution, but I miss an #Inheritance annotation from AssessmentText:
#Entity
#Table(name = "ASSESSMENT_TEXT")
#Inheritance(strategy=InheritanceType.JOINED)
#AttributeOverride(name = "localeCode", column = #Column(name = "LOCALE_CODE"))
#AssociationOverride(name = "localizedText",
joinColumns = #JoinColumn(name = "LOCALIZED_TEXT_ID"))
public class AssessmentText extends BaseText {
I had the same issue, and solved it by adding the MappedSuperClass to the persistence.xml.
I know this is also in the comments somewhere, but the useful one was hidden and I think this should be an answer, not a comment to the question.

SAXException2: A cycle is detected in the object graph. What is the case?

I have a web-service with Java class files that have been generated with NetBeans based on the database schema I have.
I get strange exceptions sometimes and one of them is this one:
javax.xml.ws.WebServiceException: javax.xml.bind.MarshalException
- with linked exception:
[com.sun.istack.internal.SAXException2: A cycle is detected in the object graph. This will cause infinitely deep XML: org.mylib.Person[ personId=1 ] ->org.mylib.TeamPerson[ teamPersonPK=org.mylib.teamPersonPK[ teamId=1, personId=1 ] ] -> org.mylib.Person[ personId=1 ]]
I have googled this exception and found some simillar cases but I still cannot understand the problem. I have just generated those classes (Person.java, Team.java, TeamPerson.java) with NetBeans so how can the problem occur?
This happens when I try to get all Persons:
Iterator iter = team.getTeamPersonCollection().iterator();
while(iter.hasNext()) {
Person person = ((TeamPerson)iter.next()).getPerson();
...
}
EDIT
If I remove the Team reference from TeamPerson I get the following error:
Internal Exception: Exception [EclipseLink-7154] (Eclipse Persistence Services - 2.2.0.v20110202-r8913): org.eclipse.persistence.exceptions.ValidationException
Exception Description: The attribute [teamPersonCollection] in entity class [class org.mylib.Team] has a mappedBy value of [team] which does not exist in its owning entity class [org.mylib.TeamPerson]. If the owning entity class is a #MappedSuperclass, this is invalid, and your attribute should reference the correct subclass.
at org.eclipse.persistence.exceptions.PersistenceUnitLoadingException.exceptionSearchingForPersistenceResources(PersistenceUnitLoadingException.java:126)
EDIT 2
Parts of the generated classes looks like this:
Team.java
public class Team implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#Column(name = "team_id")
private Integer teamId;
#Column(name = "type")
private String type;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "team")
private Collection<TeamPerson> teamPersonCollection;
Person.java
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#Column(name = "person_id")
private Integer personId;
#Column(name = "name")
private String name;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "person")
private Collection<TeamPerson> teamPersonCollection;
TeamPerson.java
public class TeamPerson implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
protected TeamPersonPK teamPersonPK;
#Basic(optional = false)
#Column(name = "timestamp")
#Temporal(TemporalType.TIMESTAMP)
private Date timestamp;
#JoinColumn(name = "team_id", referencedColumnName = "team_id", insertable = false, updatable = false)
#ManyToOne(optional = false)
private Team team;
#JoinColumn(name = "person_id", referencedColumnName = "person_id", insertable = false, updatable = false)
#ManyToOne(optional = false)
private Person person;
TeamPersonPK.java
#Embeddable
public class TeamPersonPK implements Serializable {
#Basic(optional = false)
#Column(name = "team_id")
private int teamId;
#Basic(optional = false)
#Column(name = "person_id")
private int personId;
The solution is simply to add the annotation : "#XmlTransient" (javax.xml.bind.annotation.XmlTransient) at the getter of the property that causes the cycle.
Well maybe thats is because your Person class contains the field of type TeamPerson and the TeamPerson contains the field of type Person. And the marshaller is confused un parsing such loop init?
UPD. Maybe you need to change this
#OneToMany(cascade = CascadeType.ALL, mappedBy = "team")
private Collection<TeamPerson> teamPersonCollection;
to:
#OneToMany(cascade = CascadeType.ALL, mappedBy = "teamId")
private Collection<TeamPerson> teamPersonCollection;
because field team does not exist in class TeamPerson?

Categories