hibernate会自动删除表中的行,而无需明确告知(@多人协会, Spring jpa)

carvr3hs  于 2021-08-20  发布在  Java
关注(0)|答案(1)|浏览(319)

我正在从事一个基于SpringJPA的微服务项目,其中我有两个实体,userentity和regionentity,通过多对多关系关联。以下是两个实体的(简化)代码:

@EqualsAndHashCode(of = {"id"})
@Data
@Entity
@Table(name = "users")
@Audited
public class UserEntity implements Serializable {

    @Id
    @Column(name = "userId", columnDefinition = "int", unique = true, nullable = false)
    private Long id;

    @NotAudited
    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "users_regions",
            joinColumns        = @JoinColumn(name = "userId", columnDefinition = "int", nullable = false, updatable = false),
            inverseJoinColumns = @JoinColumn(name = "regionId", columnDefinition = "varchar(50)", nullable = false, updatable = false))
    private Set<RegionEntity> regions = new HashSet<>();
}

@EqualsAndHashCode(exclude = {"users"})
@Entity
@Table(name = "regions")
@Data
@Audited
public class RegionEntity {
    @Id
    @Column(name = "name", columnDefinition = "varchar(50)", unique = true, nullable = false)
    private String name;

    @ManyToMany(mappedBy = "regions", fetch = FetchType.EAGER)
    private Set<UserEntity> users = new HashSet<>();
}

现在,我有了一个用于持久化第三个实体(callentity)示例的路由,该实体利用了前面两个实体。了解callentity还与regionentity有多对多关联,与user有多对一关联可能很有用。简而言之,这里是路由调用的方法。

public CallDTO myMethod(String userName, /* ... more stuff */) {
    UserProjection userProj = userConsumer.findByUserName(userName, UserBasicProjection.class); // from another repository, retrieve a user projection
    UserEntity user = userRepository.findById(user.getId()).orElse(null); // use that projection to initialise the user
    Set<RegionEntity> userRegions = user != null ? user.getRegions() : null;
    CallEntity newCall = new CallEntity();
    / * some actions, mainly setting values for newCall using userRegions and user... */

    CallEntity call = callRepository.save(newCall);

    return callMapper.toDTO(call);
}

问题是hibernate在保存callentity对象时会自动删除关联表中与用户区域对相关的行。例如,如果用户的id为1234,并且区域a、b和c关联,

user | region
-------------
1234 |   A
-------------
1234 |   B 
-------------
1234 |   C  
-------------

然后,表中此代码行之后的所有三行都将被删除:
callentity call=callrepository.save(newcall);
被执行。
这是当前使用的hibernate版本:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-jpamodelgen</artifactId>
    <version>5.3.12.Final</version>
</dependency>

这是执行后的控制台打印输出:

Hibernate: 
    /* get current state package-name.UserEntity */ select
        userent_.userId 
    from
        user userent_ 
    where
        userent_.userId=?
Hibernate: 
    /* get current state package-name.RegionEntity */ select
        regione_.name
    from
        region regione_ 
    where
        regione_.name=?
Hibernate: 
    /* insert package-name.CallEntity
        */ insert 
        into
            call
            (id, userid, regionid) 
        values
            (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: 
    select
        last_insert_id()
Hibernate: 
    /* delete collection package-name.UserEntity.regions */ delete 
        from
            users_regions 
        where
            userId=?
Hibernate: 
    /* insert collection
        row package-name.CallEntity.userRegions */ insert 
        into
            call_region
            (id, name) 
        values
            (?, ?)

我发现,如果我改变关系的方向(在本例中,拥有的实体是regionentity),问题就会消失。然而,这绝不是一个可行的解决方案,因为它会影响项目的其他部分。此外,我发现以前在这个网站上也有人问过类似的问题(许多人都会删除连接表条目),但不幸的是,答案并不令人满意。我尝试添加和使用方便的方法来正确地建立关联(如链接问题的答案所示),但这根本不起作用。
任何帮助都将不胜感激。
非常感谢。

o4tp2gmn

o4tp2gmn1#

最后,通过将区域集 Package 在副本中解决了该问题。
也就是说,通过替换此行:
设置userregions=user!=无效的user.getregions():null;
与:
设置userregions=userxpc!=无效的set.copyof(userxpc.getregions()):null;

相关问题