我正在使用 Spring Data JPA 和 Hibernate 映射開發 Spring Boot 應用程式,但遇到以下問題。
我有這個網路表:
CREATE TABLE IF NOT EXISTS public.network
(
id bigint NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 9223372036854775807 CACHE 1 ),
name character varying(50) COLLATE pg_catalog."default" NOT NULL,
description text COLLATE pg_catalog."default",
CONSTRAINT network_pkey PRIMARY KEY (id)
)
和這個鏈表:
CREATE TABLE IF NOT EXISTS public.chain
(
id bigint NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 9223372036854775807 CACHE 1 ),
name character varying(50) COLLATE pg_catalog."default" NOT NULL,
fk_chain_type bigint NOT NULL,
description text COLLATE pg_catalog."default",
CONSTRAINT chain_pkey PRIMARY KEY (id),
CONSTRAINT "chain_to_chain_type_FK" FOREIGN KEY (fk_chain_type)
REFERENCES public.chain_type (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
NOT VALID
)
這兩個表通過MANY TO MANY關系相互關聯,由該network_chain表實作:
CREATE TABLE IF NOT EXISTS public.network_chain
(
id bigint NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 9223372036854775807 CACHE 1 ),
fk_network_id bigint NOT NULL,
fk_chain_id bigint NOT NULL,
CONSTRAINT network_chain_pkey PRIMARY KEY (id),
CONSTRAINT chain_id_fk FOREIGN KEY (fk_chain_id)
REFERENCES public.chain (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
NOT VALID,
CONSTRAINT network_id_fk FOREIGN KEY (fk_network_id)
REFERENCES public.network (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
NOT VALID
)
基本上,fk_network_id欄位表示特定記錄在 網路表中的 id,而fk_chain_id表示特定記錄在鏈表中的 id。
I mapped these DB tables with the following Hibernate entity classes, first of all I created this Network class mapping the network table:
@Entity
@Table(name = "network")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Network implements Serializable {
private static final long serialVersionUID = -5341425320975462596L;
@Id
@Column(name = "id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
@Column(name = "name")
private String name;
@Column(name = "description")
private String description;
@ManyToMany(cascade = { CascadeType.MERGE })
@JoinTable(
name = "network_chain",
joinColumns = { @JoinColumn(name = "fk_network_id") },
inverseJoinColumns = { @JoinColumn(name = "fk_chain_id") }
)
Set<Chain> chainList;
}
As you can see it contains the @ManyToMany annotation using the @JoinTable annotation in order to join my network table with my chain table (mapped by the Chain entity class) using the previous network_chain table (implementing the MANY TO MANY relationship).
So in this @JoinTable annotation I am specifying:
- The merging table implementing the MANY TO MANY relationship: network_chain.
- the two FK on this table that are fk_network_id and fk_chain_id.
Then I have this Spring Data JPA repository class named NetworkRepository:
public interface NetworkRepository extends JpaRepository<Network, Integer> {
/**
* Retrieve a Network object by its ID
* @param id of the network
* @return the retrieve Network object
*/
Network findById(String id);
/**
* Retrieve a Network object by its name
* @param name of the network
* @return a Network object
*/
Network findByName(String name);
/**
* Retrieve the list of all the possible networks
* @return a List<Network> object: the list of the all the networks
*/
List<Network> findAll();
}
Finally I created a JUnit test class containing a method in order to test the previous repository findAll() method, this one:
@SpringBootTest()
@ContextConfiguration(classes = GetUserWsApplication.class)
@TestMethodOrder(OrderAnnotation.class)
public class NetworkTest {
@Autowired
private NetworkRepository networkRepository;
/**
* Retrieve the networks list
*/
@Test
@Order(1)
public void findAllTest() {
List<Network> networksList = this.networkRepository.findAll();
assertTrue(networksList.size() == 5, "It retrieved 5 networks");
Set<Chain> networkChain = networksList.get(0).getChainList();
assertTrue(networkChain != null, "The network chains list are not null");
}
}
The problem is that the findAll() method execute this SQL statement( I can see it into my stacktrace):
Hibernate:
select
network0_.id as id1_6_,
network0_.description as descript2_6_,
network0_.name as name3_6_
from
network network0_
and retrieve the expected List object but as you can see in the following printscreen my chainList field give an error:

It seems that it have not retrieved the chainList from my MANY TO MANY table (infact thre previous Hibernate statement seems not perform any join on the network_chain and then chain tables).
I also tried to directly access to this field by this line (my idea was that maybe Hibernate performed this join when the access to this field is explicitly performed:
Set<Chain> networkChain = networksList.get(0).getChainList();
It seems that this com.sun.jdi.InvocationException exceptions happens when I try to retrieve this field. Basically it seems that the JOINS between the MANY TO MANY table and the on the chain table is never performed.
Why? What is wrong with my code? What am I missing? How can I try to fix it?
uj5u.com熱心網友回復:
id發生這種情況是因為表 ( ) 中有一個額外的列 ( )network_chain負責many-to-many關系。
注釋將@JoinTable僅支持定義 2 個欄位,通常是id2 個表的 s。2id一起,將成為primary key連接表的 ,也稱為composite primary key。
在您的情況下,您將必須創建一個物體來表示 table network_chain。
@Entity
@Table(name = "network_chain")
public class NetworkChain {
@Id
@Column(name = "id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
@ManyToOne
private Network network;
@ManyToOne
private Chain chain;
}
public class Network implements Serializable {
//somewhere in the code
@OneToMany
List<NetworkChain> networkChains;
}
public class Chain implements Serializable {
//somewhere in the code
@OneToMany
List<NetworkChain> networkChains;
}
現在,物體NetworkChain將額外的列id作為主鍵,hibernate 將執行正確的連接來獲取資料。
超出主題,但不確定為什么該方法有一個 javadoc,findAll()它通常也是該方法的一部分,JpaRepository而且也很奇怪findById..
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/445646.html
標籤:java spring-boot hibernate spring-data-jpa hibernate-mapping
