复制的父项插入子项,而不是对其进行更新 [英] Copied parent inserts childs instead of updating them

查看:59
本文介绍了复制的父项插入子项,而不是对其进行更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的流程目前看起来如下...

My flow currently looks like the following...

  • 触发了游戏更新
  • 标记为更新"的深层复制实体.
  • 将这些深层副本实体传递到更新线程(多线程环境)
  • 打开会话,让会话更新它们
  • 等待下一次游戏更新并重复循环

那些类代表孩子/父母的关系.

And those classes represent the child/parent relationship.

/**
 * A component which marks a {@link com.artemis.Entity} as a chunk and stores its most valuable informations.
 */
@Entity
@Table(name = "chunk", uniqueConstraints = {@UniqueConstraint(columnNames={"x", "y"})}, indexes = {@Index(columnList = "x,y")})
@Access(value = AccessType.FIELD)
@SelectBeforeUpdate(false)
public class Chunk extends HibernateComponent{

    public int x;
    public int y;
    public Date createdOn;

    @OneToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "chunk_identity", joinColumns = @JoinColumn(name = "identity_id"), inverseJoinColumns = @JoinColumn(name = "id"), inverseForeignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
    @Fetch(FetchMode.JOIN)
    @BatchSize(size = 50)
    public Set<Identity> inChunk = new LinkedHashSet<>();

    @Transient
    public Set<ChunkLoader> loadedBy = new LinkedHashSet<>();

    public Chunk() {}
    public Chunk(int x, int y, Date createdOn) {
        this.x = x;
        this.y = y;
        this.createdOn = createdOn;
    }
}

/**
 * Represents a ID of a {@link com.artemis.Entity} which is unique for each entity and mostly the database id
 */
@Entity
@Table(name = "identity")
@Access(AccessType.FIELD)
@SQLInsert(sql = "insert into identity(tag, typeID, id) values(?,?,?) ON DUPLICATE KEY UPDATE id = VALUES(id), tag = values(tag), typeID = values(typeID)")
@SelectBeforeUpdate(value = false)
public class Identity extends Component {

    @Id public long id;
    public String tag;
    public String typeID;

    public Identity() {}
    public Identity(long id, String tag, String typeID) {
        this.id = id;
        this.tag = tag;
        this.typeID = typeID;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        var identity = (Identity) o;
        return id == identity.id;
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, tag, typeID);
    }
}

问题

知道为什么我的深克隆父母总是插入自己的孩子吗?以及如何在仍使用多线程的同时防止这种情况发生(当我不使用克隆的对象时,会发生休眠内部异常)...

Question

Any idea why my deep cloned parent always inserts its childs ? And how could i prevent this while still using multithreading ( When i dont use cloned objects, a hibernate internal exception occurs )...

推荐答案

我做了一些测试,发现了以下内容.

I made some test and noticed the following.

我遍历这些块并向它们添加新的实体,几乎每一帧. 该更新每隔一分钟发生一次,这意味着每个块都有许多不同的新的或旧的被删除的子代.

I iterate over the chunks and add new entities to them, nearly each frame. The update occurs every single minute onces, that means each chunk has many, many different new or old removed childs.

即使我在主线程上更新/合并那些线程,hibernate也会抛出重复的条目异常.我认为这与我们更新这些大块孩子的次数有关.可能会发生一个孩子被删除,添加,删除,添加然后停留的情况,因此休眠模式尝试复制此行为并失败.

Even when i update/merge those on the mainthread, hibernate throws an duplicate entry exception. I think this is related to the amount of times we update those chunk childs. It might happen that one child gets removed, added, removed, added and then stays, so hibernate tries to replicate this behaviour and fails.

但是我可能是错的,我添加/删除了不同的层叠设置,合并而不是更新,它们都有相同的问题.

But i might be wrong, i added/removed different cascade settings, merge instead of update and they all had the same problem.

没有真正的解决方案...绕过该异常的一种方法是添加自定义@SQLInsert批注,以忽略重复的键异常.然后,它在主线程上运行良好.它甚至似乎可以与深度克隆的实体一起使用,即使仅出现针对孩子的插入语句,也绝不会出现任何删除或删除语句.

Theres no real solution... a way to bypass that exception is to add custom @SQLInsert annotations for ignoring the duplicate key exception. It works great on the main thread then. It even seems to work with deep cloned entities, even if only insert statements for the childs appear, never any delete or remove statements.

为什么?我认为这可能会起作用,因为我在自定义sql查询中定义了重复键错误应该发生的情况,这样,每个父级都会插入其子级并覆盖旧值...因为每个子级都是一个父级的子级,所以它可以工作完美无瑕.可能在其他关系中存在问题.

Why ? I think it might work because i define in the custom sql query what should happen on a duplication key error, this way every parent inserts its child and overwrites the old values... because each child is only the child of one parent, it works flawless. Might have issues in other relations.

这可以通过合并更新的深度克隆对象或将原始对象替换为更新的深度克隆对象来解决.可能甚至还有我们在这里错过的一些休眠持久性上下文黑客.

This might be solved by merging the updated deep cloned object , or by replacing the original one with the updated deep cloned object. Probably theres even some hibernate persistence context hack we missed here.

这篇关于复制的父项插入子项,而不是对其进行更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆