Spring-Hibernate Many-to-Many : 保存一个实体,或者创建一个关系(如果它存在于数据库中)

Spring-Hibernate Many-to-Many : Save an entity, or create a relationship if it exists in the database

我是 Spring 和 Hibernate 的新手,运行 遇到了一个我几天都无法解决的问题。

在我的项目中,我在服务器和用户实体之间使用多对多关系。一个用户可以存在于多个服务器上。

我的想法是: 服务器 <-> Server_Users <-> 用户

创建 tables 的代码:

CREATE TABLE public.servers (
    id bigint NOT NULL,
    s_snowflake bigint NOT NULL,
    name character varying(64) NOT NULL
);

CREATE TABLE public.users (
    id bigint NOT NULL,
    u_snowflake bigint NOT NULL,
    name character varying(64) NOT NULL
);

CREATE TABLE public.server_users (
    id bigint NOT NULL,
    server_id bigint NOT NULL,
    user_id bigint NOT NULL
);

这是我的 class 的样子:

@Entity
@Table(name = "servers")
public class Server {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @Column(name = "s_snowflake", unique = true)
    private long snowflake;

    private String name;

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinTable(
            name = "server_users",
            joinColumns = @JoinColumn(name = "server_id"),
            inverseJoinColumns = @JoinColumn(name = "user_id")
    )
    private Set<User> users = new HashSet<>();

}

@Entity
@Table(name = "users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @Column(name = "u_snowflake", unique = true)
    private long snowflake;

    private String name;

    @ManyToMany(mappedBy = "users", targetEntity = Server.class, fetch = FetchType.EAGER)
    private Set<Server> servers = new HashSet<>();

}

这在我初始化数据时效果很好。我创建了一个服务器对象并用用户填充它,所有内容都已正确保存。

但是当我尝试保存包含已经在用户 table 中的用户的服务器时,我遇到了问题(如果我从数据库中级联删除服务器,用户不应该被删除)。

有什么方法可以配置 Hibernate 以便在必要时添加新用户,但如果用户存在,则使用 Server_Users table 将其“创建关系”到新服务器?

我试过 Cascade.SAVE_UPDATE 和其他方法,但没有结果。

成瘾:

这是我用来保存和更新的 DAO class 方法:

public abstract class AbstractDAOImpl<T> implements AbstractDAO<T> {
    public void save(T entity) {
        Session session = HibernateSessionFactoryUtil.getSessionFactory().openSession();
        Transaction trx = session.beginTransaction();
        session.save(entity);
        trx.commit();
        session.close();
    }
    public void update(T entity) {
        Session session = HibernateSessionFactoryUtil.getSessionFactory().openSession();
        Transaction trx = session.beginTransaction();
        session.update(entity);
        trx.commit();
        session.close();
    }
}

服务器添加逻辑。首先,我将它保存到数据库中,然后用用户填充Set并执行update() 如果 table with users 为空,则此方法有效,所有必要的记录和连接都在 Server_Users 和 Users tables:

中创建
public static void addServer(Guild guild) {

        Server server = new Server(Long.parseLong(guild.getId()), guild.getName());
        serverDAO.save(server);

        for (Member m : guild.getMembers()) {
            User user = new User(Long.parseLong(m.getId()), m.getUser().getName());
            user.addServer(server);
            server.addUser(user);
        }

        serverDAO.update(server);

    }

我找到了解决方案

    @Cascade({
            org.hibernate.annotations.CascadeType.SAVE_UPDATE,
            org.hibernate.annotations.CascadeType.MERGE,
            org.hibernate.annotations.CascadeType.PERSIST
    })
    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(
            name = "server_users",
            joinColumns = @JoinColumn(name = "server_sn"),
            inverseJoinColumns = @JoinColumn(name = "user_sn")
    )
    private Set<User> users = new HashSet<>();

我向服务器和用户代码添加了 CascadeTypes SAVE_UPDATE、MERGE 和 PERSIST

另外,我重新设计了base的架构,把snowflakes做成了Primary Keys,因为values都是唯一的