【问题标题】:Mapping Java Generic to String value将 Java 泛型映射到字符串值
【发布时间】:2017-06-22 16:40:24
【问题描述】:

我想持久化到 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:属性 domain.item.Attribute.value 具有未绑定类型且没有明确的目标实体。解决此通用使用问题或设置显式目标属性(例如 @OneToMany(target=) 或使用显式 @Type

  • 我只需要这个简单的表格

    • 物品
      | id:int | isTemplate:boolean |
    • 属性
      | id:int |名称:字符串 | type:String (i.e:String,Integer - > based value type) |值:字符串 | fk_item_id |

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

【问题讨论】:

    标签: hibernate generics java-8


    【解决方案1】:

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

    此外,在关系数据库中,如果没有适当的类型,您将无法保留 java 对象(您可以尝试序列化对象并将其保存为 blob,然后在 java 端对其进行反序列化:) :))

    一般:

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

      @ManyToOne(targetEntity=T_EntityClass.class) @JoinColumn(name = "") 私有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)
    )
    

    【讨论】:

      【解决方案2】:

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

      我最终采用了与您几乎相同的方法来创建额外的类包装器,但 Attribute&lt;T&gt; 确实是个好主意......它让我有能力证明 design your entity first clean and nice and do mapping latter

      【讨论】:

        猜你喜欢
        • 2012-08-21
        • 2018-07-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-09
        • 1970-01-01
        • 2014-01-14
        • 2021-11-09
        相关资源
        最近更新 更多