2

我在两个表UserKeyword之间有 ManyToMany 关系。用户是关系的所有者。如果我删除一个用户,我首先从这个用户中删除所有关键字,然后删除这个用户。这按预期工作。

但我不知道如何删除Keyword并自动删除与所有Users的关系。

到目前为止,这是我的代码。

    @实体
    @Table(name = "用户")

    公共类用户{

      @ID
      @Column(name = "id")
      @GeneratedValue
      私人整数 id;

      @Column(名称 = "名称")
      私有字符串名称;

      @ManyToMany(级联 = CascadeType.ALL,获取 = FetchType.EAGER)
      @Fetch(值 = FetchMode.SUBSELECT)
      @JoinTable(name = "user_has_keyword", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "keyword_id"))
      私有列表关键字 = new ArrayList();

      // getter 和 setter
      ...
    }

    @实体
    @Table(name = "关键字")
    公共类关键字{

      @ID
      @Column(name = "id")
      @GeneratedValue
      私人整数 id;

      @Column(name = "关键字")
      私有字符串关键字;

      @ManyToMany(mappedBy = "keywords")
      私有列表用户 = new ArrayList();

      // getter 和 setter
      ...
    }

    @Service("我的服务")
    @Transactional("事务管理器")
    公共类我的服务{

      @Resource(name = "sessionFactory")
      私人 SessionFactory 会话工厂;

      @SuppressWarnings("未选中")
      公共列表 getAllUsers() {
        会话会话 = this.sessionFactory.getCurrentSession();

        查询查询 = session.createQuery("FROM User");

        返回查询.list();
      }

      公共用户getUser(整数id){
        会话会话 = this.sessionFactory.getCurrentSession();
        return (User) session.get(User.class, id);
      }

      公共无效添加用户(用户用户){
        会话会话 = this.sessionFactory.getCurrentSession();
        会话.保存(用户);
      }

      公共无效删除用户(用户用户){
        会话会话 = this.sessionFactory.getCurrentSession();

        // 1、删除关系
        user.getKeywords().clear();
        会话.更新(用户);

        // 2、删除用户对象
        会话.删除(用户);
      }

      公共关键字getKeyword(整数id){
        会话会话 = this.sessionFactory.getCurrentSession();
        return (Keyword) session.get(Keyword.class, id);
      }

      公共关键字addKeyword(关键字关键字){
        会话会话 = this.sessionFactory.getCurrentSession();
        session.save(关键字);

        返回关键字;
      }

      公共无效删除关键字(关键字关键字){
        会话会话 = this.sessionFactory.getCurrentSession();

        // 1、删除关系
        关键字.getUsers().clear();
        session.update(关键字);

        // 2、删除用户对象
        关键字 = getKeyword(keyword.getId());
        session.delete(关键字);
      }
    }

    @控制器
    公共类 MyController {

      @Resource(name = "我的服务")
      私人的我的服务我的服务;

      @RequestMapping(value = "/add", method = RequestMethod.GET)
      公共字符串添加(模型模型){

        关键字 k = new Keyword();
        k.setKeyword("黄色");
        k = myService.addKeyword(k);

        用户 u1 = 新用户();
        u1.setName("巴特");
        u1.getKeywords().add(k);
        myService.addUser(u1);

        用户 u2 = 新用户();
        u2.setName("丽莎");
        u2.getKeywords().add(k);
        myService.addUser(u2);

        返回 ”/”;
      }

      @RequestMapping(value = "/delete/user", method = RequestMethod.GET)
      公共字符串删除用户(模型模型){

        用户 u = myService.getUser(1);
        myService.deleteUser(u);

        返回 ”/”;
      }

      @RequestMapping(value = "/delete/keyword", method = RequestMethod.GET)
      公共字符串删除关键字(模型模型){

        关键字 k = myService.getKeyword(1);
        myService.deleteKeyword(k);

        返回 ”/”;
      }

    }

如果我浏览到/delete/keyword我得到以下异常:

    org.hibernate.LazyInitializationException:未能延迟初始化角色集合:com.blabla.prototype.Keyword.users,没有会话或会话已关闭

我用谷歌搜索并尝试了许多不同的东西,但没有任何效果。

我很感激任何帮助。

非常感谢你,

马可

4

1 回答 1

2

LazyInitializationException 与删除无关。您正在控制器中加载关键字。这使服务加载关键字,而不初始化其惰性用户列表。然后将该关键字返回给控制器,并提交事务,并关闭会话,使关键字与会话分离。

然后将此分离的关键字传递给服务以将其删除。该服务因此收到一个分离的关键字,并尝试访问其用户列表。由于关键字已分离并且尚未加载用户列表,因此会导致 LazyInitializationException。

服务方法应该将要删除的关键字的 ID 作为参数,加载它,从而使用附加的关键字,然后继续删除。

现在回答您的问题,您对用户删除是正确的:您从用户中删除所有要删除的关键字,因为用户是关联的所有者。删除关键字时应用相同的逻辑:从所有引用它的用户中删除该关键字,然后删除该关键字:

public void deleteKeyword(Integer id) {
    Keyword keyword = getKeyword(id);
    for (User user : keyword.getUsers()) {
        user.removeKeyword(keyword);
    }
    session.delete(keyword);
}

请注意,在使用附加实体时,您不必调用 update()。附加实体的状态会自动透明地保存到数据库中。

于 2013-05-29T15:50:34.090 回答