2

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

在用户类

@ManyToMany(mappedBy = "usersList")
    private List<Tags> tagsList;

在标签类

@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;

现在我的业务逻辑 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(); 
    }

问题是每次我合并一个新用户以创建多对多关系时,如果现有的 userid=6201 有一个带有 2,3,4 的标签,并且新用户尝试使用标签 id 2,3,4 ,现有用户被删除,新用户合并到标签。我已经阅读了几篇关于在我的实体类中覆盖哈希和等于方法的文章,这些方法在 eclipselink 中默认被覆盖,我也无法将我的集合类型更改为 Set 或 Collection,因为 List<> 类型非常适合 json 数组。我现在很难过,已经24小时了,会不会是默认映射策略错误?我需要级联吗?

4

3 回答 3

3

在使用合并时您必须格外小心,因为它的语义(如此所述)与仅更新有点不同。由于您的关系是双向的,而用户是相反的一方,所以所有的关系持久性都将由标签方处理。假设您的标签列表包含分离的标签,这意味着所有标签都设置了它们的 id,那么您需要遍历 tagList

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); 

    } 

您还可以在 Tag 端设置 Merge cascade 选项,以节省您的第二次合并调用并让 ORM 自动管理关系。

于 2013-10-10T11:04:57.593 回答
1

以下是合并与分离实体和关系的行为方式。

@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();
........................
}

测试程序

EntityManagerFactory emf = Persistence.createEntityManagerFactory("Test");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();

User user = new User();
user.setName("User");
User managedUser = em.merge(user);
int userId = managedUser.getId();
//create a tag        
Tag tag = new Tag();
tag.setName("Tag");
tag.addUser(managedUser);
Tag managedTag = em.merge(tag);
//save the id locally
int savedId = managedTag.getId();
//managed tag was sent to UI where its name will be changed to "Changed Tag"
em.getTransaction().commit();
em.close();

//create another transaction
EntityManager em1 = emf.createEntityManager();
em1.getTransaction().begin();

//simulate a tag sent form UI 
Tag tagFromUI = new Tag();
tagFromUI.setId(savedId);
tagFromUI.setName("Changed Tag");

// I want to associate a new user to this tag
// so create a new user
User newUser = new User();        
newUser.setName("newUser");       
tagFromUI.addUser(newUser);
Tag managedTagFromUI = em1.merge(tagFromUI);


em1.getTransaction().commit();
em1.close();
emf.close();

这里是生成的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
于 2013-10-10T14:08:22.620 回答
0

在添加新条目时,您需要验证映射不重复或已存在于数据库中。为了更清楚地了解解决方案,请查看链接中提供的我的灵魂

在多对多休眠中覆盖的关系表数据

于 2021-09-10T11:46:26.467 回答