如何使用 JPA 2.1 转换连接的元素集合?
How to convert joined element collection with JPA 2.1?
我有 3 个表 user
、user_team
和 team
...
user
--------
id (number)
name (varchar)
team
--------
name (varchar)
user_team
--------
user_id (number) FK -> user.id
team_name (varchar) FK -> team.name
我想加载 User
实体,以便将团队转换为正确的类型。
@Entity
public class User implements Serializable {
@Id
@GeneratedValue( strategy = IDENTITY )
private Long id;
@Column( name = "name" )
private String name;
@ElementCollection
@JoinTable( name = "user_team",
joinColumns = @JoinColumn( name = "user_id" ) )
@Column( name = "team_name" )
@Convert( converter = TeamToStringConverter.class )
private Set<Team> teams;
}
public enum Team { NOTEAM, GEEKS, FREAKS, etc ... }
@Converter
public class TeamToStringConverter implements AttributeConverter<Team, String> {
@Override
public String convertToDatabaseColumn( Team value ) {
return value == null ? NOTEAM.name() : value.name();
}
@Override
public TEAM convertToEntityAttribute( String value ) {
return Team.from( value );
}
}
我认为问题在于它使用 TeamToStringConverter 来转换 user_team.user_id
字段而不是 user_team.team_name
字段(在 @Column 注释中指定)并且结果是异常的:
sql.SqlUtils - Attempted to convert SQLException to SQLException. Leaving it alone. [SQLState: null; errorCode: 0]
com.microsoft.sqlserver.jdbc.SQLServerException: An error occurred while converting the nvarchar value to JDBC data type INTEGER.
at com.microsoft.sqlserver.jdbc.DDC.convertStreamToObject(DDC.java:475)
at com.microsoft.sqlserver.jdbc.ServerDTVImpl.getValue(dtv.java:2536)
...
Caused by: java.lang.NumberFormatException: For input string: "NOTEAM"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
...
将映射更改为
@ElementCollection
@CollectionTable( name = "user_team",
joinColumns = @JoinColumn( name = "user_id" ) )
@Column( name = "team_name" )
@Enumerated(EnumType.STRING)
@Convert( converter = TeamToStringConverter.class )
private Set<Team> teams;
应该使用 @CollectionTable
而不是 @JoinTable
,并且 @Enumerated(EnumType.STRING)
告诉 JPA 枚举值在数据库中存储为 String
而不是 Integer
是默认值(枚举常量的索引)。
请注意,table team
在此设置中对 JPA 没有任何意义,因为它未映射到任何内容。
在低于 4.3.9 的 Hibernate 版本中,@Convert 注释不适用于集合字段。
见https://hibernate.atlassian.net/browse/HHH-9495
对于 Hibernate 较低的 4.3.9 使用 autoApply 属性:
@Converter(autoApply = true)
public class TeamToStringConverter implements AttributeConverter<Team, String> {...}
对于 Hibernate 更高版本 4.3.9 使用:
@ElementCollection
@CollectionTable( name = "user_team", joinColumns = @JoinColumn( name = "user_id" ) )
@Column( name = "team_name" )
@Convert( converter = TeamToStringConverter.class )
private Set<Team> teams;
我有 3 个表 user
、user_team
和 team
...
user
--------
id (number)
name (varchar)
team
--------
name (varchar)
user_team
--------
user_id (number) FK -> user.id
team_name (varchar) FK -> team.name
我想加载 User
实体,以便将团队转换为正确的类型。
@Entity
public class User implements Serializable {
@Id
@GeneratedValue( strategy = IDENTITY )
private Long id;
@Column( name = "name" )
private String name;
@ElementCollection
@JoinTable( name = "user_team",
joinColumns = @JoinColumn( name = "user_id" ) )
@Column( name = "team_name" )
@Convert( converter = TeamToStringConverter.class )
private Set<Team> teams;
}
public enum Team { NOTEAM, GEEKS, FREAKS, etc ... }
@Converter
public class TeamToStringConverter implements AttributeConverter<Team, String> {
@Override
public String convertToDatabaseColumn( Team value ) {
return value == null ? NOTEAM.name() : value.name();
}
@Override
public TEAM convertToEntityAttribute( String value ) {
return Team.from( value );
}
}
我认为问题在于它使用 TeamToStringConverter 来转换 user_team.user_id
字段而不是 user_team.team_name
字段(在 @Column 注释中指定)并且结果是异常的:
sql.SqlUtils - Attempted to convert SQLException to SQLException. Leaving it alone. [SQLState: null; errorCode: 0]
com.microsoft.sqlserver.jdbc.SQLServerException: An error occurred while converting the nvarchar value to JDBC data type INTEGER.
at com.microsoft.sqlserver.jdbc.DDC.convertStreamToObject(DDC.java:475)
at com.microsoft.sqlserver.jdbc.ServerDTVImpl.getValue(dtv.java:2536)
...
Caused by: java.lang.NumberFormatException: For input string: "NOTEAM"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
...
将映射更改为
@ElementCollection
@CollectionTable( name = "user_team",
joinColumns = @JoinColumn( name = "user_id" ) )
@Column( name = "team_name" )
@Enumerated(EnumType.STRING)
@Convert( converter = TeamToStringConverter.class )
private Set<Team> teams;
应该使用 @CollectionTable
而不是 @JoinTable
,并且 @Enumerated(EnumType.STRING)
告诉 JPA 枚举值在数据库中存储为 String
而不是 Integer
是默认值(枚举常量的索引)。
请注意,table team
在此设置中对 JPA 没有任何意义,因为它未映射到任何内容。
在低于 4.3.9 的 Hibernate 版本中,@Convert 注释不适用于集合字段。
见https://hibernate.atlassian.net/browse/HHH-9495
对于 Hibernate 较低的 4.3.9 使用 autoApply 属性:
@Converter(autoApply = true)
public class TeamToStringConverter implements AttributeConverter<Team, String> {...}
对于 Hibernate 更高版本 4.3.9 使用:
@ElementCollection
@CollectionTable( name = "user_team", joinColumns = @JoinColumn( name = "user_id" ) )
@Column( name = "team_name" )
@Convert( converter = TeamToStringConverter.class )
private Set<Team> teams;