将 Java 泛型映射到字符串值



我想持久化到 DB 2 实体中:

  • 属性

    @Entity
    public class Attribute<T> {
    @Id @GeneratedValue(strategy = AUTO)
    Long id;
    @ManyToOne @JoinColumn(name = "item_id")
    Item item;
    String name;
    T value;
    boolean isTemplate;
    // skip setter and getter
    }
    
  • 项目

    public class Item {
    @Id
    @GeneratedValue(strategy = AUTO)
    Long id;
    @OneToMany(cascade = ALL)
    @JoinColumn(name= "item_id")
    List<Attribute> attributes;
    private boolean isTemplate;
    // skip setter and getter
    }
    in short Item 1-->* Attribute
    
  • 我收到的错误消息,因为休眠无法映射 T 值;

    原因:org.springframework.beans.BeanInstantiationException:无法实例化 [org.hibernate.SessionFactory]:工厂方法 'sessionFactory' 引发异常;嵌套异常为 org.hibernate.AnnotationException: Property domain.item.Attribute.value 具有未绑定类型,没有显式目标实体。解决此通用用法问题或设置显式目标属性(例如 @OneToMany(target=) 或使用显式@Type

  • 我只需要这张简单的桌子

    • 项目
      | 编号:int | isTemplate:boolean |
    • 属性|
      编号:int |名称:字符串 |类型:字符串(即:字符串,整数 - 基于>的值类型) |值:字符串 |fk_item_id |

提前感谢您解决此问题的任何帮助或建议。

由于 java 类型擦除,您无法保留泛型 T。类型 T 仅存在于源中,运行时它是 Object 类型。Hibernate Doent知道如何在数据库中存储/呈现对象,它可能是任何类型 - 实体,集合,嵌入对象,一些简单的对象 - 字符串,整数.....

同样在关系数据库中,如果没有适当的类型,您将无法持久化 java 对象(您可以尝试序列化对象并将其保存为 blob,并在 java 端将其反序列化:) :)

常规:

  1. 如果 T 它是实体:需要提供一个接口/超类而不是 T,如果子类之间的差异很大,它只是一个空标记。

    @ManyToOne(目标实体=T_EntityClass.class) @JoinColumn(名称 = ") 私有 T 值;

  2. 如果它不是实体 - 看起来像你的情况: 使用除值字段以外的所有字段创建抽象实体,并从该实体子实现扩展,如字符串,整数...。

    @Entity
    @Inheritance(strategy = InheritanceType.JOINED)
    public abstract class Attribute<T> {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @ManyToOne
    @JoinColumn(name = "item_id")
    private Item item;
    @Column
    private String name;
    @Column
    boolean isTemplate;
    public abstract T getValue();
    public abstract void setValue(T value);
    ........
    }  
    

字符串实现:

@Entity
public class AttributeStringValue extends Attribute<String>{
@Column
String value;
@Override
public String getValue() {
return value;
}
@Override
public void setValue(String value) {
this.value = value;
}
}

整数实现:

@Entity
public class AttributeIntegerValue extends Attribute<Integer>{
@Column
Integer value;
@Override
public Integer getValue() {
return value;
}
@Override
public void setValue(Integer value) {
this.value = value;
}
}

结果你有3个表:

create table attribute (
id bigint generated by default as identity,
is_template boolean,
name varchar(255),
item_id bigint,
primary key (id)
)
create table attribute_integer_value (
value integer,
id bigint not null,
primary key (id)
)
create table attribute_string_value (
value varchar(255),
id bigint not null,
primary key (id)
)

sbjavateam,感谢您的详尽解释。在我尝试实施AttributeConverter后,我得出了几乎相同的结论.我坚持将T value转换为字符串。它最终使用instance of仅获取对象类型,但我无法映射其值。在您的解释Also in relational databases you can't persist java object without appropriate type中对此进行了很好的解释。

我最终采用了与您几乎相同的方法来创建额外的类包装器,但Attribute<T>真的是一个好主意......它给我带来了证明design your entity first clean and nice and do mapping latter的武器库.

最新更新