【问题标题】:Hibernate unbound type and no explicit target entity when using generic使用泛型时休眠未绑定类型且没有显式目标实体
【发布时间】:2017-12-19 21:53:09
【问题描述】:

我有以下两个类:

@Entity 
@Table(name = "criteria") 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = AbstractCriteria.TYPE, discriminatorType = DiscriminatorType.STRING)
public abstract class AbstractCriteria<T> implements Serializable {

   public static final String TYPE = "type";

   ...
   @Column(name = "clazz") private Class<T> clazz;
   ...

   protected AbstractCriteria(Class<T> clazz) {
      this.clazz = Preconditions.checkNotNull(clazz);
   }
   ...

   public abstract Predicate<T> evaluate(T value);
}

@Entity 
@DiscriminatorValue(CriteriaType.Values.DATETIME_IS_BETWEEN) 
public class DateTimeIsBetweenCriteria extends AbstractCriteria<DateTime> {
   ...
   public DateTimeIsBetweenCriteria() {
      super(DateTime.class);
   }
   ...


   @Override 
   public Predicate<DateTime> evaluate(DateTime value) {
      ...
   }
}

当我尝试保存 DateTimeIsBetweenCriteria 类的实例时,我得到了这个异常:

Exception in thread "main" org.hibernate.AnnotationException: 
Property ...AbstractCriteria.clazz has an unbound type and no explicit target entity.
Resolve this Generic usage issue or set an explicit target attribute (eg @OneToMany(target=) or use an explicit @Type

AbstractCriteria 中的方法我需要clazz,T 可以是 String、DateTime、Boolean 等。

我正在考虑制作clazz@Transient,但如果我这样做了,我仍然需要有另一列来确定要保存哪些标准,以便在从数据库中加载回标准时,我知道哪种标准是。我认为这有点 hacky。

有什么想法可以在不更改设计的情况下解决该异常吗?

非常感谢您的宝贵时间。

【问题讨论】:

    标签: java sql hibernate jpa hibernate-mapping


    【解决方案1】:

    就泛型而言,您在正确的路线上,但您正试图保留一个“类”类型的类。数据库没有可以直接映射到的数据类型(因此您的错误),我能想到的最接近的是使用字符串作为类名;

    @Column (name="className")
    private String classname;
    

    并用

    设置
    .... setClassname (DateTime.getCanonicalName());
    

    检索类;

    Class.forName(classname);
    

    但如果我对你在做什么有正确的想法,你根本不需要持久化类:所有 DateTimeIsBetweenCriteria 实例都在 DateTime 上运行 - 它是类的模板参数,而不是实例。你应该坚持你的日期,而不是班级的行为。

    【讨论】:

    • 感谢您的回答。但是,不能在数据库中持久化 Class 是不对的。您可以将clazz 列声明为varchar,并且hibernate 支持保存Class。
    • 我的立场是正确的;这不是我遇到过的 - 谢谢!答案的最后一部分有用吗?
    • 我不必保存clazz,但是正如我上面提到的。我需要使用clazz 值进行一些计算。如果我不保存它(使其瞬态),当休眠加载标准时,clazz 将是空的。
    • 这个答案是一个好的开始。你可以使clazztransient 和getClassName 用@Column 注释:hibernate 将在保存时调用getter 并在加载时调用setClassName。只需 makegetClassName 即可返回 T 类名和 setClassName to do clazz = Class.forName(classname)。
    • PCO:你为什么对我的问题投了反对票?看起来人们更喜欢在此处对其他人的帖子投反对票。
    【解决方案2】:

    我已将实现更改为不使用参数化类型:

    @Entity 
    @Table(name = "criteria") 
    @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
    @DiscriminatorColumn(name = AbstractCriteria.TYPE, discriminatorType = DiscriminatorType.STRING)
    public abstract class AbstractCriteria implements Serializable {
    
      public static final String TYPE = "type";
    
      ...
      @Column(name = "clazz") private Class clazz;
      ...
    
      protected AbstractCriteria(Class clazz) {
         this.clazz = Preconditions.checkNotNull(clazz);
      }
      ...
    
      public abstract Predicate evaluate(Object value);
    }
    
    @Entity 
    @DiscriminatorValue(CriteriaType.Values.DATETIME_IS_BETWEEN) 
    public class DateTimeIsBetweenCriteria extends AbstractCriteria {
      ...
      public DateTimeIsBetweenCriteria() {
         super(DateTime.class);
      }
      ...
    
    
      @Override 
      public Predicate evaluate(Object value) {
         if (value instanceof DateTime) {
            // do evaluation and return here.
         } else {
            throw new UserDefinedException("...");
         }
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-10-23
      • 2019-09-12
      • 1970-01-01
      • 1970-01-01
      • 2017-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多