是否可以保存引用未保存代理的实体?

Posted

技术标签:

【中文标题】是否可以保存引用未保存代理的实体?【英文标题】:Is it possible to save an entity that references an unsaved proxy? 【发布时间】:2021-02-27 15:14:02 【问题描述】:

背景

我的项目中有两个实体。一个称为“实体”,另一个是关系。我使用它们来模拟游戏中对象之间的关系。所以我的数据库中有某种树/层次结构......但在我的游戏中并非如此。我的实体看起来像这样......
@Entity
@Table(name = "entity")
@Access(AccessType.FIELD)
public class EntityPojo implements Serializable 

    @Id public long id;

    @OneToMany(mappedBy = "owner", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    public Set<RelationshipPojo> relations = new LinkedHashSet<>();


@Entity
@Table(name = "relationship")
@Access(AccessType.FIELD)
public class RelationshipPojo 

    @Id
    public long id;

    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinColumn(name = "entity_id")
    public EntityPojo owner;

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    public Set<EntityPojo> targets = new LinkedHashSet<>();


问题

我的游戏内对象之一在引用未保存的实体时可能会被保存。想象一下这种情况......在我的游戏中,我创建了多个游戏对象及其实体 pojo。 然后其中一个(磁贴)被保存,但无法获得未保存对象的代理,这会导致 ObjectNotFoundException。

        var tile = new EntityPojo();
        tile.id = 1;

        var player = new EntityPojo();
        player.id = 2;

        var proxy = session.getReference(EntityPojo.class, 2L);     // Reference to unsaved player
        var inTileRelation = new RelationshipPojo();
        inTileRelation.name = "inTile";
        inTileRelation.owner = tile;
        inTileRelation.targets.add(proxy);                          // ObjectNotFoundException
        tile.relations.add(inTileRelation);

        // Tile gets saved before player was saved... 
        syncDatabase.save(tile);

问题

为什么会发生这种情况,我该如何预防?甚至可以通过代理保存对另一个实体的引用吗?只是通过拥有实体将来拥有的 id ?我怎样才能做到这一点?

在 SQL 中,我会简单地删除约束以插入 id 本身...这在休眠中可能吗?

【问题讨论】:

【参考方案1】:

正如documentation 中所述:

获取实体引用而不初始化其数据

有时称为延迟加载,无需加载实体数据即可获得对实体的引用的能力非常重要。最常见的情况是需要在一个实体和另一个现有实体之间创建关联。

Book book = new Book();
book.setAuthor( entityManager.getReference( Person.class, personId ) );

上面的工作假设实体被定义为允许延迟加载,通常通过使用运行时代理。 在这两种情况下,如果给定实体不引用实际的数据库状态,则稍后将引发异常,当应用程序尝试以任何需要访问其数据的方式使用返回的代理时。

因此,只有当您知道您的数据库有一条具有指定 id 的记录并且您只想建立关系而不实际加载实体时,您才能使用entityManager.getReference

【讨论】:

谢谢 ^^ 当我在引用之前保存实体时,它按预期工作。

以上是关于是否可以保存引用未保存代理的实体?的主要内容,如果未能解决你的问题,请参考以下文章

对象引用未保存的瞬态实例:在刷新之前保存瞬态实例[重复]

SORM:尝试引用一个未持久化的实体

Spring-Data JPA:保存引用现有实体的新实体

数据未保存:对象引用了未保存的瞬态实例 - 在刷新之前保存瞬态实例 [重复]

在Access 2007 VBA中,未保存的表单和报表是否可以键入为“AccessObject”..?

Java JPA Hibernate保存不插入引用的实体