程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长


+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

暂无数据

只有 CascadeType.REMOVE 的双向@OneToOne 保存更改:这是不需要的

发布于2023-06-07 20:01     阅读(804)     评论(0)     点赞(22)     收藏(2)


问题:

我有两个实体,SomeEntity并且仅与级联集SomeEntityInfo存在双向一对一关系。CascadeType.REMOVE

如果SomeEntity.someEntityInfo已更改,并且SomeEntity(已经存在)已保存 -> 不应发生对SomeEntityInfo表/对象的级联数据库更新。

但是相反,相关实体也会更新

编辑/更新 换句话说:我希望SomeEntityInfo是“(有点)不可变的”。它应该在SomeEntity创建时创建,但不更新/检查版本 - 乐观锁定 - 如果SomeEntity重新保存。

我到目前为止做了什么

  • 返回结果SomeEntityInfo的 getter 中的副本SomeEntity

    通过未标记为级联 PERSIST [..] 的关系找到了一个新对象

  • (拼命地)注释

    @OneToOne(cascade = { CascadeType.REMOVE })
    @JoinColumn(name = "someentityinfo_id", updatable = false, insertable = true)
    private SomeEntityInfo someEntityInfo;
    

    与外键的ID有关,与被引用对象内部的数据无关

示例 - 数据库模式 (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);

实体代码

实体

    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]
    }

一些实体信息

    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]
    }

使用的测试场景

    // 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();

环境

EclipseLink,版本:Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd

附加信息

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?


解决方案


Changes aren't actually cascaded. What CascadeType.REMOVE means is essentially ON DELETE CASCADE, i.e. remove any orphaned rows. While there is a ON UPDATE CASCADE it is less used and only affects the other end of the foreign key.

If you make changes to an object that is handled by the ORM, the changes will be persisted. 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. EclipseLink is doing its job perfectly fine here.



所属网站分类: 技术文章 > 问答

作者:黑洞官方问答小能手

链接:http://www.javaheidong.com/blog/article/674307/ae429931f23db3de0cb0/

来源:java黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

22 0
收藏该文
已收藏

评论内容:(最多支持255个字符)