使用@MapKey注释来映射使用Map的@ManyToMany关系时遇到问题,它包含目标实体属性作为映射条目键,目标实体对象本身作为映射条目值。
申请表:
CREATE TABLE "APM_APPLICATION" (
"ID_APPLICATION" BIGINT NOT NULL,
"NAME" VARCHAR(64) NOT NULL,
"DESCRIPTION" VARCHAR(1024));
功能表:
CREATE TABLE "APM_FUNCTION" (
"ID_FUNCTION" BIGINT NOT NULL,
"ID_APPLICATION" BIGINT NOT NULL,
"NAME" VARCHAR(64) NOT NULL,
"DESCRIPTION" VARCHAR(1024));
参数表:
CREATE TABLE "APM_PARAM" (
"ID_PARAM" BIGINT NOT NULL,
"ID_APPLICATION" BIGINT NOT NULL,
"NAME" VARCHAR(64) NOT NULL,
"DESCRIPTION" VARCHAR(1024),
"VALUE" VARCHAR(64));
功能和参数连接表(带复合PK):
CREATE TABLE "APM_FUNCTION_PARAM" (
"ID_FUNCTION" BIGINT NOT NULL,
"ID_PARAM" BIGINT NOT NULL);
申请实体:
@Entity
@Table(name = "APM_APPLICATION")
public class Application {
@Id
@Column(name = "ID_APPLICATION")
private Long id;
@Column(name = "NAME")
private String name;
@Column(name = "DESCRIPTION")
private String description;
@OneToMany(mappedBy = "application")
@MapKey(name = "name")
private Map<String, Parameter> parameters = new HashMap<String, Parameter>();
@OneToMany(mappedBy = "application")
@MapKey(name = "name")
private Map<String, Function> functions = new HashMap<String, Function>();
// constructors, getters and setters omitted
public String toString() {
return "Application[id='" + id +"', " +
"name='" + name + "', " +
"parametersCount='" +parameters.size() + "', " +
"functionsCount='" + functions.size() + "']";
}
功能实体:
@Entity
@Table(name = "APM_FUNCTION")
public class Function {
@Id
@Column(name = "ID_FUNCTION")
private Long id;
@ManyToOne
@JoinColumn(name = "ID_APPLICATION")
private Application application;
@Column(name = "NAME")
private String name;
@Column(name = "DESCRIPTION")
private String description;
@ManyToMany
@JoinTable(name = "APM_FUNCTION_PARAM",
joinColumns = @JoinColumn(name = "ID_FUNCTION"),
inverseJoinColumns = @JoinColumn(name = "ID_PARAM"))
@MapKey(name = "name")
private Map<String, Parameter> parameters = new HashMap<String, Parameter>();
// constructors, getters and setters omitted
public String toString() {
return "Function[id='" + id + "', " +
"application='" + application + "', " +
"name='" + name +"', " +
"parametersCount='" + parameters.size() + "']";
}
参数实体:
@Entity
@Table(name = "APM_PARAM")
public class Parameter {
@Id
@Column(name = "ID_PARAM")
private Long id;
@ManyToOne
@JoinColumn(name = "ID_APPLICATION")
private Application application;
@ManyToMany(mappedBy = "parameters")
@MapKey(name = "name")
private Map<String, Function> functions = new HashMap<String, Function>();
@Column(name = "NAME")
private String name;
@Column(name = "VALUE")
private String value;
// constructors, getters and setters omitted
public String toString() {
return "Parameter[id='" + id + "', " +
"application='" + application + "', " +
"name='" + name + "', " +
"value='" + value + "', " +
"functionsCount='" + functions.size() + "']";
}
的pom.xml:
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- Spring Framework -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Spring Data JPA -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.3.0.RELEASE</version>
</dependency>
<!-- Spring ORM -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<!-- Apache Commons Connection Pool -->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<!-- JPA api -->
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
<version>1.0.1.Final</version>
</dependency>
<!-- Apache Derby -->
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<version>${derby.version}</version>
</dependency>
<!-- Hibernate -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
</dependencies>
<properties>
<spring.version>3.2.3.RELEASE</spring.version>
<derby.version>10.10.1.1</derby.version>
<hibernate.version>4.1.9.Final</hibernate.version>
<xdef.version>2.0.53.88</xdef.version>
</properties>
的persistence.xml:
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="apmPersistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.DerbyTenSevenDialect"/>
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.globally_quoted_identifiers" value="true"/>
</properties>
</persistence-unit>
</persistence>
弹簧master.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation=" http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<import resource="spring-jpa.xml" />
<context:property-placeholder location="META-INF/configuration.properties" />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${apm.db.driverClassName}"/>
<property name="url" value="${apm.db.url}"/>
<property name="initialSize" value="${apm.db.connPoolInitialSize}"/>
<property name="maxActive" value="${apm.db.connPoolMaxActive}"/>
</bean>
</beans>
弹簧jpa.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<jpa:repositories base-package="cz.syntea.apm.repository" />
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
depends-on="dbCreator">
<property name="dataSource" ref="dataSource"/>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
</beans>
在我尝试访问Function对象中的参数map之前,Everyhing工作正常。
执行此测试代码后(JUnit + Spring Test,appService是服务层组件,使用Spring Data JpaRepository):
@Test
@Transactional
public void testApplicationInfo() {
List<Application> apps = appService.getApplications();
for (Application app : apps) {
System.out.println("Application: " + app);
System.out.println("Parameters:" );
for (Parameter p : app.getParameters().values()) {
System.out.println("Parameter: " + p);
}
System.out.println("Functions:");
for (Function f : app.getFunctions().values()) {
System.out.println("Function: " + f); // exception is thrown in toString method, that tries to access parameters map
for (Parameter p : f.getParameters().values()) {
System.out.println("Parameter: " + p);
}
}
}
}
我遇到了以下异常:
Hibernate: select applicatio0_."ID_APPLICATION" as ID1_6_, applicatio0_."DESCRIPTION" as DESCRIPT2_6_, applicatio0_."NAME" as NAME3_6_ from "APM_APPLICATION" applicatio0_
Hibernate: select parameters0_.ID_APPLICATION as ID5_6_2_, parameters0_."ID_PARAM" as ID1_5_2_, parameters0_."NAME" as formula3_2_, parameters0_."ID_PARAM" as ID1_5_1_, parameters0_.ID_APPLICATION as ID5_5_1_, parameters0_."NAME" as NAME2_5_1_, parameters0_."RELATION" as RELATION3_5_1_, parameters0_."DATA_TYPE" as DATA4_5_1_, parameters0_.ID_VALUE as ID6_5_1_, value1_."ID_VALUE" as ID1_1_0_, value1_."BOOLEAN_SET" as BOOLEAN2_1_0_, value1_."DOUBLE_VALUE" as DOUBLE3_1_0_, value1_."INTEGER_VALUE" as INTEGER4_1_0_ from "APM_PARAM" parameters0_ left outer join "APM_VALUE" value1_ on parameters0_.ID_VALUE=value1_."ID_VALUE" where parameters0_.ID_APPLICATION=?
Hibernate: select functions0_.ID_APPLICATION as ID4_6_1_, functions0_."ID_FUNCTION" as ID1_7_1_, functions0_."NAME" as formula2_1_, functions0_."ID_FUNCTION" as ID1_7_0_, functions0_.ID_APPLICATION as ID4_7_0_, functions0_."DESCRIPTION" as DESCRIPT2_7_0_, functions0_."NAME" as NAME3_7_0_ from "APM_FUNCTION" functions0_ where functions0_.ID_APPLICATION=?
Application: Application[id='25050', name='TST_APP_1', parametersCount='2', functionsCount='2']
Parameters:
Hibernate: select functions0_.ID_PARAM as ID2_5_2_, functions0_.ID_FUNCTION as ID1_11_2_, function1_."ID_FUNCTION" as ID1_7_0_, function1_.ID_APPLICATION as ID4_7_0_, function1_."DESCRIPTION" as DESCRIPT2_7_0_, function1_."NAME" as NAME3_7_0_, applicatio2_."ID_APPLICATION" as ID1_6_1_, applicatio2_."DESCRIPTION" as DESCRIPT2_6_1_, applicatio2_."NAME" as NAME3_6_1_ from "APM_FUNCTION_PARAM" functions0_ inner join "APM_FUNCTION" function1_ on functions0_.ID_FUNCTION=function1_."ID_FUNCTION" left outer join "APM_APPLICATION" applicatio2_ on function1_.ID_APPLICATION=applicatio2_."ID_APPLICATION" where functions0_.ID_PARAM=?
Parameter: Parameter[id='25051', application='Application[id='25050', name='TST_APP_1', parametersCount='2', functionsCount='2']', name='b', value='20', functionsCount='1']
Hibernate: select functions0_.ID_PARAM as ID2_5_2_, functions0_.ID_FUNCTION as ID1_11_2_, function1_."ID_FUNCTION" as ID1_7_0_, function1_.ID_APPLICATION as ID4_7_0_, function1_."DESCRIPTION" as DESCRIPT2_7_0_, function1_."NAME" as NAME3_7_0_, applicatio2_."ID_APPLICATION" as ID1_6_1_, applicatio2_."DESCRIPTION" as DESCRIPT2_6_1_, applicatio2_."NAME" as NAME3_6_1_ from "APM_FUNCTION_PARAM" functions0_ inner join "APM_FUNCTION" function1_ on functions0_.ID_FUNCTION=function1_."ID_FUNCTION" left outer join "APM_APPLICATION" applicatio2_ on function1_.ID_APPLICATION=applicatio2_."ID_APPLICATION" where functions0_.ID_PARAM=?
Parameter: Parameter[id='25050', application='Application[id='25050', name='TST_APP_1', parametersCount='2', functionsCount='2']', name='a', value='100', functionsCount='2']
Functions:
SQL Error: 20000, SQLState: 42X04
Column 'A5.PARAMETERS0_.NAME' is either not in any table in the FROM list or appears within a join specification and is outside the scope of the join specification or appears in a HAVING clause and is not in the GROUP BY list. If this is a CREATE or ALTER TABLE statement then 'A5.PARAMETERS0_.NAME' is not a column in the target table.
看起来Hibernate试图在Map本身中找到@MapKey注释中指定名称的属性,而不是目标实体。
是否可以将具有目标实体属性的Map用作ManyToMany关系中的键?我怎样才能实现它?
感谢您的时间。