我正在使用以下转换器将一组字符串作为逗号分隔值(带有转义符)保留在单个VARCHAR数据库列中:
VARCHAR
public class StringSetConverter implements AttributeConverter<Set<String>, String> { @Override public String convertToDatabaseColumn(Set<String> stringSet) { if (stringSet == null) { return null; } // remove null-strings and empty strings, escape commas return stringSet.stream().filter(Objects::nonNull).filter(s -> s.length() > 0) .map(s -> s.replace(",", "\\,")) .sorted().collect(Collectors.joining(",")); } @Override public Set<String> convertToEntityAttribute(String dbString) { if (dbString == null) { return new HashSet<>(); } Set<String> result = new HashSet<>(); String[] items = dbString.split("(?<=[^\\\\]),"); for (String item : items) { if (item.length() > 0) { result.add(item.replace("\\,", ",")); } } return result; } }
在JPA实体上的用法:
@Column(name = "GRANTED_PRIVILEGES", nullable = false, length = 4000) @Convert(converter = StringSetConverter.class) private Set<String> grantedPrivileges; @Column(name = "DENIED_PRIVILEGES", nullable = false, length = 4000) @Convert(converter = StringSetConverter.class) private Set<String> deniedPrivileges;
转换器的工作原理非常好 -字符串集可以正确保留,并且可以读取而不会出现任何问题。
唯一的警告是启动使用这些实体的Spring Boot应用程序时 Hibernate记录 的 错误 :
ERROR o.h.m.i.MetadataContext : HHH015007: Illegal argument on static metamodel field injection : anonymized.AuthorityDO_#grantedPrivileges; expected type : org.hibernate.metamodel.internal.SingularAttributeImpl; encountered type : javax.persistence.metamodel.SetAttribute ERROR o.h.m.i.MetadataContext : HHH015007: Illegal argument on static metamodel field injection : anonymized.AuthorityDO_#deniedPrivileges; expected type : org.hibernate.metamodel.internal.SingularAttributeImpl; encountered type : javax.persistence.metamodel.SetAttribute
Hibernate的JPA有什么问题AttributeConverter?除了记录错误外,Hibernate最终可以与转换器一起很好地工作- 那么问题出在哪里,我该如何解决?
AttributeConverter
您的映射是错误的,因为您尝试对奇异属性使用collection。根据JPA规范(请参见 6.2.1.1规范元模型 部分):
对于zclass声明的每个持久性具有集合值的属性X,其中元素类型z为Z,元模型类必须包含如下声明: 如果的收集类型z为java.util.Set,则 public static volatile SetAttribute<X, Z> z;
对于zclass声明的每个持久性具有集合值的属性X,其中元素类型z为Z,元模型类必须包含如下声明:
z
X
Z
java.util.Set
public static volatile SetAttribute<X, Z> z;
但是,Hibernate所期待的,你会使用@ElementCollection,@OneToMany或@ManyToMany协会收集属性。
@ElementCollection
@OneToMany
@ManyToMany
我建议您对自定义类型使用一些包装器类:
public class StringSet { private Set<String> stringSet; // ... } public class StringSetConverter implements AttributeConverter<StringSet, String> { @Override public String convertToDatabaseColumn(StringSet stringSet) { // ... } @Override public StringSet convertToEntityAttribute(String dbString) { // ... } } @Column(name = "GRANTED_PRIVILEGES", nullable = false, length = 4000) @Convert(converter = StringSetConverter.class) private StringSet grantedPrivileges;