简体   繁体   English

具有仅CascadeType.REMOVE的双向@OneToOne保存更改:不需要

[英]Bi-directional @OneToOne with ONLY CascadeType.REMOVE saves changes: that is not wanted

The problem: 问题:

I have two entities, SomeEntity and SomeEntityInfo in a bi-directional one-to-one relation with only CascadeType.REMOVE cascading set. 我只有两个CascadeType.REMOVE级联集, SomeEntity具有双向一对一关系的SomeEntitySomeEntityInfo

If SomeEntity.someEntityInfo is changed, and SomeEntity is (already existing) saved -> there shouldn't happen a cascading database update to the SomeEntityInfo table / object. 如果更改SomeEntity.someEntityInfo ,并且保存(已经存在) SomeEntity >不应对SomeEntityInfo表/对象进行级联数据库更新。

But instead, the related entity is updated too 但是相反,相关实体也被更新

edit / update In other words: I want the SomeEntityInfo to be "(somewhat-)immutable". 编辑/更新换句话说:我希望SomeEntityInfo是“(某种程度上)不可变的”。 It should be created when SomeEntity is created, but not updated / version checked - optimistic locking - if SomeEntity is re-saved. 它应在创建SomeEntity创建,但不进行更新/检查版本-乐观锁定-如果重新保存SomeEntity

what i did so far 我到目前为止所做的

  • Returning a copy of SomeEntityInfo in the getter of SomeEntity results in SomeEntityInfo的getter中返回SomeEntityInfo的副本SomeEntity导致

    a new object was found through a relationship that was not marked cascade PERSIST [..] 通过未标记为层叠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 与外键的ID有关,与所引用对象内部的数据无关

Example - DB schema (mysql db) 示例-数据库架构(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 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 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 EclipseLink,版本:Eclipse Persistence Services-2.5.2.v20140319-9ad6abd

Additional Information 附加信息

The specification ( http://wiki.eclipse.org/Introduction_to_EclipseLink_JPA_(ELUG)#.40OneToOne ) sais: 规范( http://wiki.eclipse.org/Introduction_to_EclipseLink_JPA_(ELUG)#.40OneToOne )表示:

cascade – By default, JPA does not cascade any persistence operations to the target of the association. 级联–默认情况下,JPA不会将任何持久性操作级联到关联目标。

that is not the case (changes are cascaded).. what am I missing here? 情况并非如此(更改是级联的)..我在这里缺少什么?

SomeEntityInfo instance is managed , meaning any changes to it will be saved, unrelated to cascading. SomeEntityInfo实例是受管理的 ,这意味着对它的任何更改都将被保存,与级联无关。 Take a look at this answer for more details. 请查看此答案以获取更多详细信息。

Changes aren't actually cascaded. 更改实际上不是级联的。 What CascadeType.REMOVE means is essentially ON DELETE CASCADE , ie remove any orphaned rows. CascadeType.REMOVE含义实质上是ON DELETE CASCADE ,即删除任何孤立的行。 While there is a ON UPDATE CASCADE it is less used and only affects the other end of the foreign key. 尽管存在ON UPDATE CASCADE ,但使用较少,仅影响外键的另一端。

If you make changes to an object that is handled by the ORM, the changes will be persisted. 如果您对由ORM处理的对象进行更改,则更改将被保留。 However it has nothing to do with cascading. 但是,它与级联无关。

So if you don't want to update SomeEntityInfo in the database, don't update it in your code. 因此,如果您不想更新数据库中的SomeEntityInfo ,请不要在代码中对其进行更新。 EclipseLink is doing its job perfectly fine here. EclipseLink在这里做得很好。

The answers below are correct, I just wanted to add that the em.persist() isn't doing anything - it is a no-op because the loadedSe instance is a managed entity. 下面的答案是正确的,我只是想补充一点,em.persist()没有做任何事情-它是空操作,因为loadSe实例是一个托管实体。 If it were not a managed entity, the JPA specification requires that calling persist on an existing, unmanaged entity instance result in an exception - either on the persist or flush call, or when the transaction tries to commit. 如果不是托管实体,则JPA规范要求在现有的非托管实体实例上进行持久化调用会导致异常-持久化或刷新调用,或者在事务尝试提交时。

All changes to managed entities are synchronized to the database when flush is called or the transaction commits. 当调用flush或提交事务时,对托管实体的所有更改都将同步到数据库。 All entities accessed from an EntityManager are managed by that EntityManager context until they are cleared. 从EntityManager访问的所有实体均由该EntityManager上下文管理,直到清除它们为止。 If you called em.clear before making the changes, the changes would not have been picked up by the commit. 如果在进行更改之前调用了em.clear,则提交将不会拾取更改。 Another alternative is to use the read-only query hint on the find operation: http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/Query_Hints#Read_Only 另一种选择是在查找操作上使用只读查询提示: http : //wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/Query_Hints#Read_Only

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 OneToOne双向映射中的唯一约束 - Unique constraint in OneToOne bi-directional mapping 没有 CascadeType.REMOVE 的 CascadeType.ALL 更改持久化行为 - CascadeType.ALL without CascadeType.REMOVE changes persist behavior 如何在休眠中仅删除@OneToOne双向映射的一侧 - How to delete only one side of @OneToOne bi-directional mapping in hibernate 双向关联 - Bi-directional association 双向参考 - Bi-directional reference JPA CascadeType.REMOVE不会删除reshipsship的子级 - JPA CascadeType.REMOVE not deleting children of a relashionship 如何在双向关系中只更新孩子而不是父母 - How to update only the child and not the parent in a bi-directional relationship 使用@OneToOne进行双向关系时,“ org.hibernate.TypeMismatchException:提供的类型错误的ID” - “org.hibernate.TypeMismatchException: Provided id of the wrong type” when using @OneToOne for a bi-directional relation 错误:类型不匹配-如何使用spring-mvc形式保持休眠的双向OneToOne映射 - ERROR: type mismatch - how to persist with hibernate a bi-directional OneToOne mapping using spring-mvc forms 使用非主端上的主/外键映射来映射JPA双向@OneToOne - Mapping a JPA bi-directional @OneToOne with primary/foreign key mapping on non-owning side
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM