java框架hibernate多对多如何进行关联查询

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java框架hibernate多对多如何进行关联查询相关的知识,希望对你有一定的参考价值。

比如我有学生表 课程表 和中间表三个表 对应的实体类(不必要的信息就省略了)

public class Student
private int id;
private String name;

@Id
public int getId()

//其他省略



public class Course
private int id;
private String name;
@Id
public int getId()

//其他省略


中间表
public class StudentCourse
private int id;
private Student s;
private Course c;

@Id
public int getId()


@ManyToOne
public Student getS()


@ManyToOne
public Course getC()




现在要查询的是student类的id,name以及一个student选了什么course?怎么写hql语句?
返回值尽量是List<Student>
关联的course id和name也要查出来
实体类结构就这样了 没法改了

我写的hql是“select s from Student s join s.scs”
这样写的hql解析的sql放数据库里能查出正确的记录 但是这样的hql却只能得到第一条记录 这是怎么回事?

多对多需要一个关联表,你用的是注解,你可以在多的一方的另一方引用的list上面,
比如用户和角色,他们是多对多的关系,你可以写上:
/**User表中的其他的属性*/
@LazyCollection(LazyCollectionOption.FALSE)
@ManyToMany()
@JoinTable(name = "TB_USER_ROLE", joinColumns = @JoinColumn(name = "USER_ID"), inverseJoinColumns = @JoinColumn(name = "ROLE_ID"))
private List<Role> roles;

这样就在数据库中创建了TB_USER_ROLE这个关联表,

然后在ROLE这个实体类中也要配置一个多对多的关系。如下:
// 对应关联的用户集合
@ManyToMany(mappedBy = "roles")
private List<User> users;

这样就可以啦,
参考技术A 多对多需要一个关联表,你用的是注解,你可以在多的一方的另一方引用的list上面,
比如用户和角色,他们是多对多的关系,你可以写上:
/**User表中的其他的属性*/
@LazyCollection(LazyCollectionOption.FALSE)
@ManyToMany()
@JoinTable(name = "TB_USER_ROLE", joinColumns = @JoinColumn(name = "USER_ID"), inverseJoinColumns = @JoinColumn(name = "ROLE_ID"))
private List<Role> roles;

这样就在数据库中创建了TB_USER_ROLE这个关联表,

然后在ROLE这个实体类中也要配置一个多对多的关系。如下:
// 对应关联的用户集合
@ManyToMany(mappedBy = "roles")
private List<User> users;

这样就可以啦,

Hibernate:n-n关联关系

  • 背景:

  在实际开发中我们会遇到表的多对多关联,比如:一篇博客文章,它可以同时属于JAVA分类、Hibernate分类。

  因此,我们在hibernate的学习文章系列中,需要学会如何使用hibernate来实现多对多的关联关系。

  在hibernate实现多对多的关联关系中,也是需要创建一个中间表来存储、维护两张表的多对多的关系。具体实现有两种可选方案:单向多对多、双向多对多。

  • 单向多对多:

 新建一个java project,定义项目名称为:hibernate07;在src下添加hibernate.cfg.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE hibernate-configuration PUBLIC
 3         "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
 4         "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
 5 <hibernate-configuration>
 6     <session-factory>
 7         <property name="hibernate.connection.username">root</property>
 8         <property name="hibernate.connection.password">123456</property>
 9         <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
10         <property name="hibernate.connection.url">jdbc:mysql://localhost/hibernate_01</property>
11 
12         <!-- <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> 
13             <property name="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</property> -->
14         <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
15 
16         <property name="hibernate.show_sql">true</property>
17 
18         <property name="hibernate.format_sql">true</property>
19 
20         <property name="hibernate.hbm2ddl.auto">update</property>
21 
22         <property name="hibernate.current_session_context_class">thread</property>
23 
24         <property name="hibernate.c3p0.max_size">500</property>
25         <property name="hibernate.c3p0.min_size">20</property>
26         <property name="hibernate.c3p0.max_statements">10</property>
27         <property name="hibernate.c3p0.timeout">2000</property>
28         <property name="hibernate.c3p0.idle_test_period">2000</property>
29         <property name="hibernate.c3p0.acquire_increment">10</property>
30 
31         <mapping resource="com/dx/hibernate06/n2n/ProductCategory.hbm.xml" />        
32         <mapping resource="com/dx/hibernate06/n2n/ProductItem.hbm.xml" />
33             
34     </session-factory>
35 </hibernate-configuration>
View Code

在src下创建包com.dx.hibernate06.n2n,在包下创建:

ProductCategory.java(在category这个类中创建了一个Set<ProductItem> productItems 属性)

 1 package com.dx.hibernate06.n2n;
 2 
 3 import java.util.HashSet;
 4 import java.util.Set;
 5 
 6 public class ProductCategory {
 7     private Integer id;
 8     private String name;
 9     private String detail;
10     private Set<ProductItem> productItems = new HashSet<>();
11 
12     public ProductCategory() {
13 
14     }
15 
16     public ProductCategory(String name, String detail) {
17         super();
18         this.name = name;
19         this.detail = detail;
20     }
21 
22     public Integer getId() {
23         return id;
24     }
25 
26     public void setId(Integer id) {
27         this.id = id;
28     }
29 
30     public String getName() {
31         return name;
32     }
33 
34     public void setName(String name) {
35         this.name = name;
36     }
37 
38     public String getDetail() {
39         return detail;
40     }
41 
42     public void setDetail(String detail) {
43         this.detail = detail;
44     }
45 
46     public Set<ProductItem> getProductItems() {
47         return productItems;
48     }
49 
50     public void setProductItems(Set<ProductItem> productItems) {
51         this.productItems = productItems;
52     }
53 
54 }
View Code

ProductCategory.hbm.xml

 1 <?xml version="1.0"?>
 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 4 <!-- Generated 2017-6-7 22:33:53 by Hibernate Tools 3.5.0.Final -->
 5 <hibernate-mapping package="com.dx.hibernate06.n2n">
 6     <class name="ProductCategory" table="PRODUCT_CATEGORY">
 7         <id name="id" type="java.lang.Integer">
 8             <column name="ID" />
 9             <generator class="native" />
10         </id>
11         <property name="name" type="java.lang.String">
12             <column name="NAME" />
13         </property>
14         <property name="detail" type="java.lang.String">
15             <column name="DETAIL" />
16         </property>
17 
18         <set name="productItems" table="PRODUCT_CATEGORY_ITEM">
19             <key>
20                 <column name="CATEGORY_ID" />
21             </key>
22             <many-to-many class="ProductItem" column="ITEM_ID"></many-to-many>
23         </set>
24     </class>
25 </hibernate-mapping>
View Code

备注:在ProductCategory.hbm.xml的set节点我们定义的table属性,并定义了many-to-many节点用来指向ProductItem。

ProductItem.java

 1 package com.dx.hibernate06.n2n;
 2 
 3 public class ProductItem {
 4     private Integer id;
 5     private String title;
 6     private double price;
 7 
 8     public ProductItem() {
 9     }
10 
11     public ProductItem(String title, double price) {
12         super();
13         this.title = title;
14         this.price = price;
15     }
16 
17     public Integer getId() {
18         return id;
19     }
20 
21     public void setId(Integer id) {
22         this.id = id;
23     }
24 
25     public String getTitle() {
26         return title;
27     }
28 
29     public void setTitle(String title) {
30         this.title = title;
31     }
32 
33     public double getPrice() {
34         return price;
35     }
36 
37     public void setPrice(double price) {
38         this.price = price;
39     }
40 
41 }
View Code

ProductItem.hbm.xml

 1 <?xml version="1.0"?>
 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 4 <!-- Generated 2017-6-7 22:33:53 by Hibernate Tools 3.5.0.Final -->
 5 <hibernate-mapping>
 6     <class name="com.dx.hibernate06.n2n.ProductItem" table="PRODUCT_ITEM">
 7         <id name="id" type="java.lang.Integer">
 8             <column name="ID" />
 9             <generator class="native" />
10         </id>
11         <property name="title" type="java.lang.String">
12             <column name="TITLE" />
13         </property>
14         <property name="price" type="double">
15             <column name="PRICE" />
16         </property>
17     </class>
18 </hibernate-mapping>
View Code

测试类TestMain.java 

 1 package com.dx.hibernate06.n2n;
 2 
 3 import java.util.Date;
 4 import java.util.Set;
 5 
 6 import org.hibernate.Session;
 7 import org.hibernate.SessionFactory;
 8 import org.hibernate.Transaction;
 9 import org.hibernate.boot.Metadata;
10 import org.hibernate.boot.MetadataSources;
11 import org.hibernate.boot.model.naming.ImplicitNamingStrategyComponentPathImpl;
12 import org.hibernate.boot.registry.StandardServiceRegistry;
13 import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
14 import org.hibernate.metamodel.internal.MapMember;
15 import org.junit.After;
16 import org.junit.Before;
17 import org.junit.Test;
18 
19 public class TestMain {
20     private SessionFactory sessionFactory = null;
21     private Session session = null;
22     private Transaction transaction = null;
23 
24     @Before
25     public void init() {
26         StandardServiceRegistry standardRegistry = new StandardServiceRegistryBuilder().configure().build();
27         Metadata metadata = new MetadataSources(standardRegistry).getMetadataBuilder().applyImplicitNamingStrategy(ImplicitNamingStrategyComponentPathImpl.INSTANCE).build();
28 
29         sessionFactory = metadata.getSessionFactoryBuilder().build();
30         session = sessionFactory.getCurrentSession();
31         transaction = session.beginTransaction();
32     }
33 
34     @After
35     public void destory() {
36         transaction.commit();
37         session.close();
38         sessionFactory.close();
39     }
40 }
View Code

 测试代码:

添加测试函数1:

 1     @Test
 2     public void testInsert() {
 3         ProductCategory category1 = new ProductCategory();
 4         category1.setName("category1");
 5         category1.setDetail("Detail");
 6 
 7         ProductCategory category2 = new ProductCategory();
 8         category2.setName("category2");
 9         category2.setDetail("Detail");
10 
11         ProductItem item1 = new ProductItem();
12         item1.setTitle("item1");
13         item1.setPrice(110.00);
14 
15         ProductItem item2 = new ProductItem();
16         item2.setTitle("item2");
17         item2.setPrice(110.00);
18 
19         category1.getProductItems().add(item1);
20         category1.getProductItems().add(item2);
21 
22         category2.getProductItems().add(item1);
23         category2.getProductItems().add(item2);
24 
25         session.save(category1);
26         session.save(category2);
27 
28         session.save(item1);
29         session.save(item2);
30     }

控制台打印sql

 1 Hibernate: 
 2     
 3     create table PRODUCT_CATEGORY (
 4        ID integer not null auto_increment,
 5         NAME varchar(255),
 6         DETAIL varchar(255),
 7         primary key (ID)
 8     ) engine=InnoDB
 9 Hibernate: 
10     
11     create table PRODUCT_CATEGORY_ITEM (
12        CATEGORY_ID integer not null,
13         ITEM_ID integer not null,
14         primary key (CATEGORY_ID, ITEM_ID)
15     ) engine=InnoDB
16 Hibernate: 
17     
18     create table PRODUCT_ITEM (
19        ID integer not null auto_increment,
20         TITLE varchar(255),
21         PRICE double precision,
22         primary key (ID)
23     ) engine=InnoDB
24 Hibernate: 
25     
26     alter table PRODUCT_CATEGORY_ITEM 
27        add constraint FKgqq9f2yg5b52m390yk15c8u28 
28        foreign key (ITEM_ID) 
29        references PRODUCT_ITEM (ID)
30 Hibernate: 
31     
32     alter table PRODUCT_CATEGORY_ITEM 
33        add constraint FKtajc52s55t4fk8864s63hsuv2 
34        foreign key (CATEGORY_ID) 
35        references PRODUCT_CATEGORY (ID)
View Code

查询数据库结果信息:

添加测试函数2:

1     @Test
2     public void testSelect() {
3         ProductCategory category = (ProductCategory) session.get(ProductCategory.class, 1);
4         System.out.println(category.getName());
5 
6         System.out.println(category.getProductItems().size());
7     }

后台执行sql及结果:

 1 Hibernate: 
 2     select
 3         productcat0_.ID as ID1_0_0_,
 4         productcat0_.NAME as NAME2_0_0_,
 5         productcat0_.DETAIL as DETAIL3_0_0_ 
 6     from
 7         PRODUCT_CATEGORY productcat0_ 
 8     where
 9         productcat0_.ID=?
10 category1
11 Hibernate: 
12     select
13         productite0_.CATEGORY_ID as CATEGORY1_1_0_,
14         productite0_.ITEM_ID as ITEM_ID2_1_0_,
15         productite1_.ID as ID1_2_1_,
16         productite1_.TITLE as TITLE2_2_1_,
17         productite1_.PRICE as PRICE3_2_1_ 
18     from
19         PRODUCT_CATEGORY_ITEM productite0_ 
20     inner join
21         PRODUCT_ITEM productite1_ 
22             on productite0_.ITEM_ID=productite1_.ID 
23     where
24         productite0_.CATEGORY_ID=?
25 2
  • 双向多对多:

 实现双向多对多,需要再ProductItem的另一端也定义Set属性:Set<ProductCategory> productCategories。还需要在ProductItem.hbm.xml中添加set节点,节点属性配置与ProductCategory.hbm.xml中set节点配置对调。

修改ProductItem.java(在类中添加属性:Set<ProductCategory> productCategories):

 1 package com.dx.hibernate06.n2n;
 2 
 3 import java.util.HashSet;
 4 import以上是关于java框架hibernate多对多如何进行关联查询的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate之多对多篇

框架 day32 Hibernate,一级缓存,关联关系映射(一对多,多对多)

Hibernate、Spring 框架和多对多

(转)Hibernate框架基础——多对多关联关系映射

Hibernate 与同一实体的递归多对多关联

hibernate框架学习笔记9:多对多关系案例