The problem:
I have two entities, SomeEntity
and SomeEntityInfo
in a bi-directional one-to-one relation with only CascadeType.REMOVE
cascading set.
If SomeEntity.someEntityInfo
is changed, and SomeEntity
is (already existing) saved -> there shouldn't happen a cascading database update to the SomeEntityInfo
table / object.
But instead, the related entity is updated too
edit / update
In other words: I want the SomeEntityInfo
to be "(somewhat-)immutable". It should be created when SomeEntity
is created, but not updated / version checked - optimistic locking - if SomeEntity
is re-saved.
what i did so far
Returning a copy of
SomeEntityInfo
in the getter ofSomeEntity
results ina new object was found through a relationship that was not marked cascade PERSIST [..]
(desperately)annotating with
@OneToOne(cascade = { CascadeType.REMOVE }) @JoinColumn(name = "someentityinfo_id", updatable = false, insertable = true) private SomeEntityInfo someEntityInfo;
is related to the ID of the foreign key, not to the data inside the referenced object
Example - DB schema (mysql db)
CREATE TABLE someentity (
id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
version INT(11) NULL DEFAULT NULL,
someentityinfo_id INT(11) UNSIGNED NULL DEFAULT NULL,
PRIMARY KEY (id)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB;
CREATE TABLE someentityinfo (
id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
version INT(11) NULL DEFAULT NULL,
status varchar(255) DEFAULT NULL,
PRIMARY KEY (id)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB;
ALTER TABLE someentity
ADD INDEX FK_someentityinfo_id (someentityinfo_id);
ALTER TABLE someentity
ADD CONSTRAINT FK_someentityinfo_id FOREIGN KEY (someentityinfo_id) REFERENCES someentityinfo (id);
Entity Code
SomeEntity
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Version;
@Entity
@Table(name = "someentity")
public class SomeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Version
private Integer version;
@OneToOne(cascade = { CascadeType.REMOVE })
@JoinColumn(name = "someentityinfo_id")
private SomeEntityInfo someEntityInfo;
[getter/setter]
}
SomeEntityInfo
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Version;
@Entity
@Table(name = "someentityinfo")
public class SomeEntityInfo {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Version
private Integer version;
private String status;
@OneToOne(mappedBy = "someEntityInfo")
private SomeEntity someEntity;
[getter/setter]
}
Used test scenario
// create and persist entity and its info object
em.getTransaction().begin();
SomeEntity se = new SomeEntity();
SomeEntityInfo seInfo = new SomeEntityInfo();
se.setSomeEntityInfo(seInfo);
seInfo.setSomeEntity(se);
seInfo.setStatus("status 1");
em.persist(se);
em.persist(se.getSomeEntityInfo());
em.getTransaction().commit();
// load created entity, modify its info and expect
// to NOT update the info object while saving the entity again
em.getTransaction().begin();
SomeEntity loadedSe = em.find(SomeEntity.class, Integer.valueOf(se.getId()));
loadedSe.getSomeEntityInfo().setStatus("do not cascade update");
// as Chris said below, not necessary to explicit save managed entity again
// em.persist(loadedSe);
em.getTransaction().commit();
Environment
EclipseLink, version: Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd
Additional Information
The specification (http://wiki.eclipse.org/Introduction_to_EclipseLink_JPA_(ELUG)#.40OneToOne) sais:
cascade – By default, JPA does not cascade any persistence operations to the target of the association.
that is not the case (changes are cascaded).. what am I missing here?