2017-06-22 72 views
0

我想坚持到DB 2实体:映射Java泛型字符串值

  • 属性

    @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 
    
  • 错误消息,我得到的,因为Hibernate不能映射T值;

    所致:org.springframework.beans.BeanInstantiationException:无法实例[org.hibernate.SessionFactory实例]:出厂方法 '的sessionFactory' 抛出异常;嵌套的异常是org.hibernate.AnnotationException:属性domain.item.Attribute.value具有未绑定的类型和没有明确的目标实体。解决这个一般使用问题,或者设定一个明确的目标属性(如@OneToMany(目标=),或使用一个明确的@Type

  • 我只需要这个简单的表

    • 项目
      | ID: INT | isTemplate:布尔|
    • 属性
      | ID:INT |名称:字符串|类型:字符串(例如:字符串,整数 - >基于价值型)|值:字符串| fk_item_id |

在此先感谢您提供任何帮助或建议以解决此问题。

回答

2

由于java类型擦除Type Erasure,您不能坚持通用T.类型T只在源中存在,在运行时它的类型为Object。休眠doent的知道如何存储/呈现数据库中的对象它可能是任何类型 - 实体,集合,嵌入对象,一些简单的对象 - 字符串,整数.....

也在关系数据库中,你不能坚持java没有适当类型的对象(可以尝试序列化对象,并将其保存为BLOB和Java方面去序列化:) :))

一般:

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

    @ManyToOne(targetEntity = T_EntityClass.class) @JoinColumn(name =“”) private T value;

  2. 如果它不是实体 - 看起来像你的情况: 创建抽象实体,其中包含除value字段外的所有字段,并从此实体的子实现中继承,如String,Integer ....

    @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) 
) 
0

sbjavateam,谢谢你的详细解释。在我尝试执行AttributeConverter之后,我得出了几乎相同的结论。我坚持要将T value转换为String。它最终使用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