In OpenJPA, I try to remove an entity with a bi-directional mapping to another entity. I did "find" and then "remove" but I have got an exception of "Encountered deleted object". Can someone provide me a working example?
#Entity
#Table(name="Order")
public class Order implements Serializable {
#EmbeddedId
private OrderPK pk;
...
#OneToOne(cascade=CascadeType.ALL, mappedBy="order")
private Invoice invoice;
}
#Entity
#Table(name="Invoice")
public class Invoice implements Serializable {
#EmbeddedId
private InvoicePK pk;
...
#OneToOne
#PrimaryKeyJoinColumn
private Order order;
}
#Embeddable
public class OrderPK implements Serializable {
private String id;
private Date date;
...
}
#Embeddable
public class InvoicePK implements Serializable {
private String id;
private Date date;
...
}
First, I add them in a single transaction and commit:
Order order = new Order(...);
order.set...
Invoice invoice = new Invoice(...);
invoice.set...
order.setInvoice(invoice);
invoice.setOrder(order);
em.persist(order);
Then when I try to remove the order, I expect the invoice will be gone too:
Order order = em.find(Order.class, orderPK); em.remove(order);
but I have an exception instead saying:
Encountered deleted object "org.apache.openjpa.enhance.Order$pcsubclass-
Order-OrderPK#92882281" in persistent field "Invoice.order" of managed
object "Invoice$pcsubclass-InvoicePK#92882281" during flush.
Related
I have an #Entity class, with an #Id annotation and a #OneToOne annotation on the same field. Usually this would not be a problem, but the entity class of the field with these annotations uses a composite key. This is causing more complications than I anticipated.
Here is the entity class that is posing the problem:
#Entity
public class ReportDetails implements Serializable {
#Id
#OneToOne
private MachineLine machineLine;
}
And here is the MachineLine entity class that is being used as an ID in ReportDetails:
#Entity
#IdClass(MachineLine.MachineLineKey.class)
public class MachineLine {
#Id
#ManyToOne
private Machine machine;
#Id
private long lineIndex;
public static class MachineLineKey implements Serializable {
private Machine machine;
private long lineIndex;
}
}
I have left out any extra fields and the getters and setters from these class definitions, to save space.
When I try to run my application it gives the following exception:
java.lang.IllegalArgumentException: This class [class ReportDetails] does not define an IdClass
When I put an #IdClass annotation on ReportDetails it then requires defining the individual fields of whatever class I define in #IdClass, like in MachineLine. However, I am trying to avoid doing this, in favour of having the whole MachineLine entity returned whenever a ReportDetails entity is retrieved from the database.
Is there a way of having MachineLine as the ID field of ReportDetails, without having to define extra fields within ReportDetails?
This is what JPA calls a "derived identity". You might try something like this:
ReportDetails:
#Entity
public class ReportDetails implements Serializable {
// all attributes map by the relationship: AttributeOverride is not allowed
#EmbeddedId
private MachineLine.Id id;
#MapsId
#JoinColumns({
#JoinColumn(name="machineId", referencedColumnName="machineId"),
#JoinColumn(name="machineLineIndex", referencedColumnName="index")
})
#OneToOne
private MachineLine machineLine;
// ...
}
MachineLine:
#Entity
public class MachineLine {
#EmbeddedId
private Id id;
#MapsId("machineId") // maps machineId attribute of embedded id
#ManyToOne
private Machine machine;
// ...
#Embeddable
public static class Id implements Serializable {
private long machineId; // corresponds to PK type of Machine
private long index;
// ...
}
}
Machine:
#Entity
public class Machine {
#Id
private long id;
#OneToMany(mappedBy = "machine")
private List<MachineLine> lines;
// ...
}
Derived identities are discussed (with examples) in the JPA 2.2 spec in section 2.4.1.
I have the following code that defines the relationship between three tables.
public class Attachment implements Serializable {
#Id
#Column(name="attachment_id")
private int attachmentId;
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name="reference_id")
private Reference reference;
#OneToMany(mappedBy="attachment")
private List<Reference> references;
MORE STUFF;
}
public class Uuid implements Serializable {
#Id
#Column("name=uuid_id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int uuidId;
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name="reference_id")
private Reference reference;
MORE STUFF
}
public class Reference implements Serializable {
#Id
#Column(name="reference_id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int referenceId;
#OneToMany(mappedBy="reference")
private List<Attachment> attachments;
#ManyToOne(cascade=CascadeType.MERGE)
#JoinColumn(name="attachment_id")
private Attachment attachment;
#OneToMany(mappedBy="reference")
private List<Uuid> uuids;
MORE STUFF
}
I have some more code that picks the specific "uuid" object/row that needs to be deleted, and the idea is that anything in the other tables that needs deleting because they share the same reference_id should be deleted too. The code that does this is:
try {
final EntityTransaction transaction = em.getTransaction();
transaction.begin();
em.remove(data);
transaction.commit();
} catch (final PersistenceException e) {
throw new CPDPersistenceException(e);
}
When the delete is performed it throws Exception "Cannot delete or update parent row: a foreign key constraint fails. I posted something on a variation of this before. Does anybody have any ideas? Thanks for your time.
You have one one-to-many relationship between Reference and Attachment defined but also a many-to-one between Reference and Attachment (and vice versus), this will never work. You should have either one of them, not both, or a many-to-many relationship.
Fix that and it should be much easier to delete objects.
For instance:
public class Attachment implements Serializable {
#Id
#Column(name="attachment_id")
private int attachmentId;
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name="reference_id")
private Reference reference;
//MORE STUFF;
}
public class Reference implements Serializable {
#Id
#Column(name="reference_id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int referenceId;
#OneToMany(mappedBy="reference")
private List<Attachment> attachments;
#OneToMany(mappedBy="reference")
private List<Uuid> uuids;
/bMORE STUFF
}
I am trying to implemet inheritance hierarchy as mentioned in below image using hibernate Joined strategy.
Since Joined strategy creates table for entity regardless of entity class is Concrete or Abstract.
I don't want to create separate table for "CompanyEmployee" so I declared it as mapped superclass, but I should able to query this class/subclasses in polymorphic way.
Since it is mapped superclass I can't do this, and if I declare it to be entity it will create table which I want to avoid.
So, is there any way I can achieve this? I am thinking about mixed inheritance but from below quote it doesn't seems to be a good solution.
Mixed Inheritance
We should begin this section by saying that the practice of mixing inheritance types within a single
inheritance hierarchy is currently outside the specification. We are including it because it is both useful
and interesting, but we are offering a warning that it might not be portable to rely on such behavior,
even if your vendor supports it.
Inheritance hierarchy
#Entity
#Table(name="j_employee")
#Inheritance(strategy=InheritanceType.JOINED)
#DiscriminatorColumn(name="emp_type", discriminatorType=DiscriminatorType.STRING)
public abstract class JEmployee extends AuditLog implements Serializable {
#Id
#Basic
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="employee_id")
private Integer employeeId;
#Basic
#Temporal(TemporalType.DATE)
#Column(name="join_date")
private Date joinDate;
#OneToOne
#JoinColumn(name="person_id", nullable=false)
private Person person;
#Column(name="emp_type", updatable=false, insertable=false)
private String empType;
//Getters and Setters
}
#Entity
#Table(name="j_contract_employee")
#DiscriminatorValue(value="JContractEmployee")
#PrimaryKeyJoinColumn(name="contract_employee_id", referencedColumnName="employee_id")
public class JContractEmployee extends JEmployee implements Serializable {
#Basic
#Column(name="daily_rate")
private Integer dailyRate;
#Basic
#Column(name="term")
private Integer term;
//Getters and Setters
}
//Don't want to create table for this class, but I should able to query this clas/subclasses in polymorphic way
#MappedSuperclass
public abstract class JCompanyEmployee extends JEmployee implements Serializable {
#Basic
#Column(name="vacation")
private Integer vacation;
//Getters and Setters
public Integer getVacation() {
return vacation;
}
public void setVacation(Integer vacation) {
this.vacation = vacation;
}
}
#Entity
#Table(name="j_part_time_employee")
#Access(AccessType.FIELD)
#DiscriminatorValue(value="JPartTimeEmployee")
#PrimaryKeyJoinColumn(name="part_time_employee_id", referencedColumnName="employee_id")
public class JPartTimeEmployee extends JCompanyEmployee implements Serializable {
#Basic
#Column(name="hourly_rate")
private Integer hourlyRate;
//Getters and Setters
}
#Entity
#Table(name="j_full_time_employee")
#Access(AccessType.FIELD)
#DiscriminatorValue(value="JFullTimeEmployee")
public class JFullTimeEmployee extends JCompanyEmployee implements Serializable {
#Basic
#Column(name="salary")
private Integer salary;
#Basic
#Column(name="penion")
private Integer pension;
//Getters and Setter
}
I have the following situation: a student belongs to a team, a team can have many students. At registration time the student doesn't know the assigned team, so the team object in student class should be null. How to force the insertion of student with null team object without getting this error:
org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : com.af.domain.Student.team -> com.af.domain.Team
I tried cascade=CascadeType.ALL but it also ads a new team in the database.
Student class
#Entity
#Table(name = "student")
public class Student implements DomainModel{
#Id
#GeneratedValue
private Integer idStudent;
private String firstname;
private String lastname;
private String username;
private String password;
#ManyToOne
#JoinColumn(name="idTeam", nullable=true)
private Team team;
}
Team class
#Entity
#Table
public class Team implements DomainModel{
#Id
#GeneratedValue
private Integer idTeam;
private String teamName;
#OneToMany(mappedBy="team")
private Set<Student> students;
}
Persistence class
public class GenericDAOImpl<T extends DomainModel> implements GenericDAO<T> {
public void save(T object) {
EntityManager entityManager = entityManagerFactory
.createEntityManager();
entityManager.getTransaction().begin();
try {
entityManager.persist(object);
} catch(NullPointerException ex){
ex.printStackTrace();
}finally {
entityManager.getTransaction().commit();
entityManager.close();
}
}
}
You can use detach option with entity manager.
entityManager.detach --- This will detach that particular parent object from the main entity object which you want to persist or merge.
I have a problem, I have two entity Job and JobPK
Job class looks like this sample code :
#Entity
#IdClass(JobPK.class)
#Table(name="JOB")
#Inheritance
#DiscriminatorColumn(name="JOB_TYPE")
public abstract class Job implements Serializable {
#Id
#Column(name="FOLDER_ID")
private BigDecimal folderId;
#Id
#ColumnDefinition(position = 1)
private String name;
#Column(name="JOB_TYPE",insertable=false,updatable=false)
private String jobType;
...
}
and JobPk :
public class JobPK implements Serializable {
private static final long serialVersionUID = -3266336718203527905L;
#Column(name="JOB_TYPE",insertable=false,updatable=false)
private String jobType;
#Id
private String name;
#Id
#Column(name="FOLDER_ID")
private BigDecimal folderId;
......
}
I have two class which extends Job : CalculatingJob and ImportingJob
Now I wont to use :
getEntityManager().find(CalculatingJob.class, new JobPK (BigDecimal.valueOf(folderId),name))
and I have problem because I must fill i JobPK descriminator value field. If I don't do that I've got Null Pointer Exception. Descriminator value is in key by default I think but I don't want put information about descriminator value explicite during JobPk creating. I thought that Entity which extends from Job will fill this field automaticaly. Any Idea to bypass this problem, maybe I can get Annotation #DescriminatorVale from CalculatingJob and then put into constructor JobPk
Thanks for Help
Try this configuration for Hierarchy structure
Job.java
#Table(name = "JOB")
#Inheritance
#IdClass(JobPK.class)
#DiscriminatorColumn(name = "JOB_TYPE", discriminatorType = DiscriminatorType.STRING)
public abstract class Job implements java.io.Serializable {
}
CalculatingJob.java
#Entity
#DiscriminatorValue("CalculatingJob")
public class CalculatingJob extends Job {
}
ImportingJob.java
#Entity
#DiscriminatorValue("ImportingJob")
public class ImportingJob extends Job {
}
JobPK.java
public class JobPK implements Serializable {
}
The discriminator value is entered by hibernate.