使用泛型时 Hibernate 未绑定类型和没有明确的目标实体
Hibernate unbound type and no explicit target entity when using generic
我有以下两个class:
@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 class 的实例时,我遇到了这个异常:
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
我需要 clazz
用于 AbstractCriteria
中的方法,并且 T
可以是 String、DateTime、Boolean 等
我正在考虑制作 clazz
@Transient
,但如果我这样做,我仍然必须有另一列来确定要保存的条件,以便在从数据库中加载条件时,我知道它是哪种标准。我认为这有点 hacky。
关于如何在不更改设计的情况下解决该异常的任何想法?
非常感谢你的宝贵时间。
就泛型而言,您的做法是正确的,但您正在尝试保留类型为 "Class" 的 class。数据库没有可以直接映射到的数据类型(因此你的错误),我能想到的最接近的是使用字符串作为 classname;
@Column (name="className")
private String classname;
并设置为
.... setClassname (DateTime.getCanonicalName());
检索 class;
Class.forName(classname);
但是如果我对你正在做的事情有正确的想法,你根本不需要坚持 class:所有 DateTimeIsBetweenCriteria 实例都对 DateTime 进行操作 - 它是class,不是实例。你应该坚持你的日期,而不是 class.
的行为
我已将实现更改为不使用参数化类型:
@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("...");
}
}
}
我有以下两个class:
@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 class 的实例时,我遇到了这个异常:
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
我需要 clazz
用于 AbstractCriteria
中的方法,并且 T
可以是 String、DateTime、Boolean 等
我正在考虑制作 clazz
@Transient
,但如果我这样做,我仍然必须有另一列来确定要保存的条件,以便在从数据库中加载条件时,我知道它是哪种标准。我认为这有点 hacky。
关于如何在不更改设计的情况下解决该异常的任何想法?
非常感谢你的宝贵时间。
就泛型而言,您的做法是正确的,但您正在尝试保留类型为 "Class" 的 class。数据库没有可以直接映射到的数据类型(因此你的错误),我能想到的最接近的是使用字符串作为 classname;
@Column (name="className")
private String classname;
并设置为
.... setClassname (DateTime.getCanonicalName());
检索 class;
Class.forName(classname);
但是如果我对你正在做的事情有正确的想法,你根本不需要坚持 class:所有 DateTimeIsBetweenCriteria 实例都对 DateTime 进行操作 - 它是class,不是实例。你应该坚持你的日期,而不是 class.
的行为我已将实现更改为不使用参数化类型:
@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("...");
}
}
}