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却只能得到第一条记录 这是怎么回事?
比如用户和角色,他们是多对多的关系,你可以写上:
/**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>
在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 }
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>
备注:在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 }
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>
测试类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 }
测试代码:
添加测试函数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)
查询数据库结果信息:
添加测试函数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多对多如何进行关联查询的主要内容,如果未能解决你的问题,请参考以下文章