从多对多连接表中检索行的 HQL 查询

Posted

技术标签:

【中文标题】从多对多连接表中检索行的 HQL 查询【英文标题】:HQL query for retrive rows from ManyToMany Join Table 【发布时间】:2014-04-27 11:38:52 【问题描述】:

我正在开发用户可以订阅组织的网站。 当我要实现订阅功能时,我面临以下问题。

在排序中,我想创建 ManyToMany 连接表的模型类,用于从表中检索行以检查用户订阅了哪些组织。 在 Hibernate 中,我无法在没有主键的情况下创建表。但在连接表中,一个用户可以订阅多个组织,一个组织有多个订阅者,所以主键重复,我得到了异常 ERROR: Duplicate entry '1' for key 'PRIMARY'

hibernate.cfg.xml包含

<mapping class="model.User"/>
<mapping class="model.Post"/>
<mapping class="model.UserSubscribes"/>

User.java

package model;
    
@Entity
@Table(name="user",
        uniqueConstraints = @UniqueConstraint(columnNames="email")
        )
@org.hibernate.annotations.Entity(dynamicUpdate=true,selectBeforeUpdate=true)

public class User implements Serializable 
    
    @Id 
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private long userId;//1
    private String email;//1
    private String password;//
    
    public User(long userId, String email, String password)
        this.userId = userId;
        this.email = email;
        this.password = password;
    
    
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(
            name="UserSubscribes",
            joinColumns= @JoinColumn(name="userId",referencedColumnName="userId") ,
            inverseJoinColumns= @JoinColumn(name="orgId", referencedColumnName="orgId") 
    )
    private Collection<Organisation> orgSubscribes = new ArrayList<Organisation>();
    

    //Getter & Setter
    

Organisation.java

package model;

@Entity
@Table(name="org",
        uniqueConstraints = @UniqueConstraint(columnNames="email")
        )
@org.hibernate.annotations.Entity(dynamicUpdate=true,selectBeforeUpdate=true)

public class Organisation implements Serializable 

    @Id 
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private long orgId;
    private String email;
    private String password;
    
    public Organisation(long orgId, String email, String password)
        this.orgId = orgId;
        this.email = email;
        this.password = password;
    
    
    //Getter & Setter

UserSubscribes.java

package model;

@Entity
@Table(name="UserSubscribes")
public class UserSubscribes implements Serializable 
    
    @Id 
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private long userId;
    private long orgId;
    
    //Getter & Setter

订阅.java

package view.action;

public class Subscribe extends ActionSupport 

    public String execute()
        
        Session session = HibernateUtill.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        
        System.out.println("Subscribbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
        
        User u1 = new User(1, "ppp", "ppp");
        User u2 = new User(2, "qqq", "qqq");
        Organisation o1 = new Organisation(1, "ppp", "ppp");
        Organisation o2 = new Organisation(2, "qqq", "qqq");
        Organisation o3 = new Organisation(3, "www", "www");
        Organisation o4 = new Organisation(4, "eee", "eee");
        
        session.save(o1);
        session.save(o2);
        session.save(o3);
        session.save(o4);
        session.save(u1);
        session.save(u2);
        
        u1.getOrgSubscribes().add(o1);
        u1.getOrgSubscribes().add(o2);
        u1.getOrgSubscribes().add(o3);
        
        session.saveOrUpdate(u1);
        
        session.getTransaction().commit();
        
        return SUCCESS;
    

我得到了这个输出和错误

Subscribbbbbbbbbbbbbbbbbbbbbbbbbbbbb
Hibernate: insert into org (email, password) values (?, ?)
Hibernate: insert into org (email, password) values (?, ?)
Hibernate: insert into org (email, password) values (?, ?)
Hibernate: insert into org (email, password) values (?, ?)
Hibernate: insert into user (email, password) values (?, ?)
Hibernate: insert into user (email, password) values (?, ?)
Hibernate: insert into UserSubscribes (userId, orgId) values (?, ?)
Hibernate: insert into UserSubscribes (userId, orgId) values (?, ?)
Apr 27, 2014 4:43:52 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
WARN: SQL Error: 1062, SQLState: 23000
Apr 27, 2014 4:43:52 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
ERROR: Duplicate entry '1' for key 'PRIMARY'

如果我从 hibernate.cfg.xml 映射中删除 &lt;mapping class="model.UserSubscribes"/&gt;,那么它就像以下输出一样完美。

Subscribbbbbbbbbbbbbbbbbbbbbbbbbbbbb
Hibernate: insert into org (email, password) values (?, ?)
Hibernate: insert into org (email, password) values (?, ?)
Hibernate: insert into org (email, password) values (?, ?)
Hibernate: insert into org (email, password) values (?, ?)
Hibernate: insert into user (email, password) values (?, ?)
Hibernate: insert into user (email, password) values (?, ?)
Hibernate: insert into UserSubscribes (userId, orgId) values (?, ?)
Hibernate: insert into UserSubscribes (userId, orgId) values (?, ?)
Hibernate: insert into UserSubscribes (userId, orgId) values (?, ?)

输出是

但如果不将此表映射到 hibernate.cfg.xml 文件中,我将无法从中检索行(使用 HQL)。 如果这个问题有任何可能的解决方案,我真的很感谢你。 提前谢谢你。

【问题讨论】:

HQL: Hibernate query with ManyToMany的可能重复 【参考方案1】:

不应将连接表映射为实体。您只需要 User、Organization 和这两个实体之间的 ManyToMany 关联。

在排序中,我想创建 ManyToMany 连接表的模型类,用于从表中检索行以检查用户订阅了哪些组织

这可以通过关联来完成:

User user = em.find(User.class, userId);
Set<Organization> organizations = user.getOrganizations();

或使用简单的 JPQL 查询:

select o from User u inner join u.organizations o where u.id = :userId

【讨论】:

不知道什么是em.find(User.class, userId) 能解释一下吗。顺便说一句,我在回答时使用 session.get(User.class, userId) 来实现它。谢谢@JBNizet 您使用 JPA 标记了您的问题,所以我认为您使用的是标准 JPA API(em 是 EntityManager),而不是旧的专有 Hibernate API。 em.find(User.class, userId)session.get(User.class, userId) 做同样的事情。 好的,我明白了em.find(User.class, userId) 用于 JPA,但现在我使用 Hibernate API。再次感谢 :)【参考方案2】:

感谢 JB 尼泽特

我按照您的建议实现了代码,并且运行良好。 这是解决的代码。

GetSubscriber.java

package view.action;

public class GetSubscriber extends ActionSupport 

    public String execute()

        Session session = HibernateUtill.getSessionFactory().getCurrentSession();
        session.beginTransaction();

        User u = (User) session.get(User.class, (long)1);
        List<Organisation> s = (List<Organisation>) u.getOrgSubscribes();

        for(int i=0;i<s.size();i++)
            System.out.println(s.get(i).getOrgId() + "  " + s.get(i).getEmail());
        

        return SUCCESS;
    

输出:

1  ppp
2  qqq
3  www

【讨论】:

List&lt;Organisation&gt; s = new ArrayList&lt;Organisation&gt;(); 没用:您创建一个空的 ArrayList,然后通过将另一个列表分配给 s 立即忘记它。您只需要List&lt;Organisation&gt; s = u.getOrgSubscribes();。你也不应该需要任何演员表。 u.getOrgSubscribes() 应该返回一个 List&lt;Organisation&gt;

以上是关于从多对多连接表中检索行的 HQL 查询的主要内容,如果未能解决你的问题,请参考以下文章

使用 laravel 从多对多检索数据

从多对多关系中获取数据

如何在laravel中从多对多关系中检索多个记录

如何从多对多表中选择一对一关系

从多对多关系中获取结果

Hibernate - 从多对多关系访问字段