Rest jpa:合并多对多之前的记录时会被删除

Rest jpa:合并多对多之前的记录时会被删除,rest,jpa,ejb,many-to-many,eclipselink,Rest,Jpa,Ejb,Many To Many,Eclipselink,我有一个Users和Tags表,还有一个user_tag_xref表,其中包含多对多关系。现在netbeans为我生成实体类(使用eclipselink),下面是实体映射关系 关于用户类 @ManyToMany(mappedBy = "usersList") private List<Tags> tagsList; @ManyToMany(mappedBy=“usersList”) 私有列表标记列表; 关于标签类 @JoinTable(name = "USERS_TAG_

我有一个Users和Tags表,还有一个user_tag_xref表,其中包含多对多关系。现在netbeans为我生成实体类(使用eclipselink),下面是实体映射关系

关于用户类

@ManyToMany(mappedBy = "usersList")
    private List<Tags> tagsList;
@ManyToMany(mappedBy=“usersList”)
私有列表标记列表;
关于标签类

@JoinTable(name = "USERS_TAG_XREF", joinColumns = {
        @JoinColumn(name = "TAG_ID", referencedColumnName = "TAG_ID")}, inverseJoinColumns = {
        @JoinColumn(name = "USER_ID", referencedColumnName = "USER_ID")})
    @ManyToMany
    private List<Users> usersList;
@JoinTable(name=“USERS\u TAG\u XREF”,joinColumns={
@JoinColumn(name=“TAG\u ID”,referencedColumnName=“TAG\u ID”)},inverseJoinColumns={
@JoinColumn(name=“USER\u ID”,referencedColumnName=“USER\u ID”)})
@许多
私有列表用户列表;
现在,在我的业务逻辑RESTfull服务中,json客户机使用此方法

 @POST
    @Path("/registration2/tag") 
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
    public Response registration2_3(List<Tags>tagList,@Context HttpServletRequest req){

         Profile p =(Profile) registerMap.get(req.getSession().getId());
     Users u = em.find(Users.class,p.getUserId());


    for(Tags t : tagList){
        t.getUsersList().add(u);
        u.getTagsList().add(t); 
        em.merge(t);
        em.merge(u); 

    }     
   logger.log(Level.INFO, "the taglist created for user");

       return Response.ok(u,MediaType.APPLICATION_JSON).build(); 
    }
@POST
@路径(“/registration2/tag”)
@使用(MediaType.APPLICATION_JSON)
@产生(MediaType.APPLICATION_JSON)
公共响应注册2_3(ListtagList,@Context HttpServletRequest req){
Profile p=(Profile)registerMap.get(req.getSession().getId());
Users u=em.find(Users.class,p.getUserId());
用于(标记t:标记列表){
t、 getUsersList().add(u);
u、 getTagsList().add(t);
em.merge(t);
em.merge(u);
}     
logger.log(Level.INFO,“为用户创建的标记列表”);
返回Response.ok(u,MediaType.APPLICATION_JSON).build();
}
问题是每次我合并一个新用户以创建多对多关系时,如果一个现有的userid=6201有一个带有2,3,4的标记,并且新用户试图使用它来标记id 2,3,4,
现有用户将被删除,新用户将合并到标记中。我已经阅读了几篇关于重写实体类中的hash和equals to方法的文章,这些方法在eclipselink中默认被重写,而且我不能将我的集合类型更改为Set或collection,因为列表类型对于json数组非常有效。我现在很难过,已经24小时了,难道默认的映射策略是错误的吗?我需要卡斯卡斯德吗

使用merge时必须格外小心,因为它的语义(如上所述)与仅使用update有点不同。 由于您的关系是双向的,而用户是反向的,所以所有关系的持久性都将由 标签侧边。假设您的标记列表包含分离的标记,这意味着所有标记都设置了它们的id,那么您需要迭代标记列表

Tag managedTag = em.merge(t);
这需要注意,如果t是新实例(非托管),那么将返回它的持久表示 如果实例的id被设置,那么ORM将使用数据库中的数据(或者一级/二级缓存中的数据,如果存在的话)创建一个托管实例。返回的实例是托管的实例

for(Tags t : tagList){
        Tag managedTag = em.merge(t);
        managedTag.getUsersList().add(u);
        u.getTagsList().add(t);         
       User managedUser =  em.merge(u); 

    } 

您还可以在标记端设置Merge cascade选项,以保存第二次合并调用,并让ORM自动管理关系

使用merge时必须格外小心,因为它的语义(如上所述)与仅使用update有点不同。 由于您的关系是双向的,而用户是反向的,所以所有关系的持久性都将由 标签侧边。假设您的标记列表包含分离的标记,这意味着所有标记都设置了它们的id,那么您需要迭代标记列表

Tag managedTag = em.merge(t);
这需要注意,如果t是新实例(非托管),那么将返回它的持久表示 如果实例的id被设置,那么ORM将使用数据库中的数据(或者一级/二级缓存中的数据,如果存在的话)创建一个托管实例。返回的实例是托管的实例

for(Tags t : tagList){
        Tag managedTag = em.merge(t);
        managedTag.getUsersList().add(u);
        u.getTagsList().add(t);         
       User managedUser =  em.merge(u); 

    } 

您还可以在标记端设置Merge cascade选项,以保存第二次合并调用,并让ORM自动管理关系

以下是合并如何处理分离的实体和关系

@Entity
public class Tag {

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

    private String     name;

    @ManyToMany(cascade=CascadeType.ALL)
    private List<User> users = new ArrayList();
.......................
}


@Entity
public class User {

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

    private String    name;
    @ManyToMany(mappedBy="users",cascade=CascadeType.ALL)
    private List<Tag> tags = new ArrayList();
........................
}
下面是生成的SQL和相应的解释

//First transaction begins
insert into User (name) values ('User');
insert into Tag (name) values ('Tag');
insert into Tag_User (tags_id, users_id) values (1, 1);
//First transaction ends
//Second transaction begins
// Since a detached tag is merged, hibernate queries for tag id 1 to load it in persistent context
//This tag is associated with a user
select tag0_.id as id1_3_1_, tag0_.name as name2_3_1_, users1_.tags_id as tags_id1_3_3_, user2_.id as users_id2_4_3_, user2_.id as id1_5_0_, user2_.name as name2_5_0_ from Tag tag0_ left outer join Tag_User users1_ on tag0_.id=users1_.tags_id left outer join User user2_ on users1_.users_id=user2_.id where tag0_.id=1;
//copies the state of detached tag from UI to the managed tag and sends update
update Tag set name='Changed Tag' where id=1;
//since merge is cascaded, hibernate looks for the user list of supplied tag and sees an transient User
// the transient instance is merged (created new in  database as it is not yet persisted)
insert into User (name) values ('newUser');
// merge is called on this new managed instance and the resulted instance is set in the managed Tag instance automatically 
//but for this the old relation has to be broken
delete from Tag_User where tags_id=1;
// and the new relation has to be added in database
insert into Tag_User (tags_id, users_id) values (1, 2);
//second transaction ends

下面是合并如何处理分离的实体和关系

@Entity
public class Tag {

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

    private String     name;

    @ManyToMany(cascade=CascadeType.ALL)
    private List<User> users = new ArrayList();
.......................
}


@Entity
public class User {

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

    private String    name;
    @ManyToMany(mappedBy="users",cascade=CascadeType.ALL)
    private List<Tag> tags = new ArrayList();
........................
}
下面是生成的SQL和相应的解释

//First transaction begins
insert into User (name) values ('User');
insert into Tag (name) values ('Tag');
insert into Tag_User (tags_id, users_id) values (1, 1);
//First transaction ends
//Second transaction begins
// Since a detached tag is merged, hibernate queries for tag id 1 to load it in persistent context
//This tag is associated with a user
select tag0_.id as id1_3_1_, tag0_.name as name2_3_1_, users1_.tags_id as tags_id1_3_3_, user2_.id as users_id2_4_3_, user2_.id as id1_5_0_, user2_.name as name2_5_0_ from Tag tag0_ left outer join Tag_User users1_ on tag0_.id=users1_.tags_id left outer join User user2_ on users1_.users_id=user2_.id where tag0_.id=1;
//copies the state of detached tag from UI to the managed tag and sends update
update Tag set name='Changed Tag' where id=1;
//since merge is cascaded, hibernate looks for the user list of supplied tag and sees an transient User
// the transient instance is merged (created new in  database as it is not yet persisted)
insert into User (name) values ('newUser');
// merge is called on this new managed instance and the resulted instance is set in the managed Tag instance automatically 
//but for this the old relation has to be broken
delete from Tag_User where tags_id=1;
// and the new relation has to be added in database
insert into Tag_User (tags_id, users_id) values (1, 2);
//second transaction ends

如果你正在观看,有人能帮忙吗?请在对t.getUserList()调用merge时,它中有什么?t和标记列表来自哪里?如上所述,在调用merge时,必须注意标记实际上反映了数据库中所需的内容。如果只是部分完成,则使用部分数据覆盖完整数据。还有,删除的是什么,只是联接表中的引用吗?Chris提出的好问题。join表中的引用被删除了吗?t.getUserList()包含(一个用户)一个在一对多关系中有3个标记的用户\u id 6201,2,3,t和标记列表来自json数组,我可以很好地读取数组,但是根据shailendra先生写的代码,如果新用户\u id 6202使用post方法发送标记为1,2,3的标记列表,用户id 6202将具有1,2,3,从而从数据库中删除用户6201。如果您正在查看,有人可以提供帮助吗?请在对t.getUserList()调用merge时,它中有什么?t和标记列表来自哪里?如上所述,在调用merge时,必须注意标记实际上反映了数据库中所需的内容。如果只是部分完成,则使用部分数据覆盖完整数据。还有,删除的是什么,只是联接表中的引用吗?Chris提出的好问题。join表中的引用被删除了吗?t.getUserList()包含(一个用户)一个在一对多关系中有3个标记的用户\u id 6201,2,3,t和标记列表来自json数组,我可以很好地读取数组,但是根据shailendra先生写的代码,如果新用户\u id 6202使用post方法发送标记为1,2,3的标记列表,用户_id 6202将有1,2,3,从而从dbi中删除用户6201。我尝试了您的代码,但它仍然给出相同的结果,我修改了您的代码,认为可能需要将托管标记添加到u.getTagList().add(managedTag);答复