我正在开发一个应用程序,该应用程序处理几种不同类型的产品,即旅游(如观光旅游或类似旅游),这些旅游的变体和选项(可以与旅游一起预订的可选附加组件)
上述所有产品类型,思想名称,描述,持续时间等都存在无数的属性,因此建模这些属性的最合适方法是使用(抽象)Product
类和单个产品表以及Tour
,TourVariant
和Option
的三个单独的子类,每个子类都直接扩展Product
。游览变体和选项都完全属于一个父游览,因此,每个游览可以具有任意数量的变体和选项。
省略非必需位,这是我们当前的设置:
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="subclazz", discriminatorType=DiscriminatorType.STRING)
@DiscriminatorValue(value="-") // this "root" class is essentially abstract
public class Product implements Comparable<Product> {
private Long id;
//more properties that are used for any type of product
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
//getters & setters, hashcode, equals and compareTo methods
}
@Entity
@DiscriminatorValue(value="TOUR")
public class Tour extends Product {
private SortedSet<Option> options = new TreeSet<Option>();
private SortedSet<TourVariant> variants = new TreeSet<TourVariant>();
//some tour specific properties
@OneToMany(mappedBy="tour",fetch=FetchType.LAZY)
@SortNatural
@OnDelete(action=OnDeleteAction.CASCADE)
@Cascade({CascadeType.PERSIST, CascadeType.MERGE, CascadeType.SAVE_UPDATE})
public SortedSet<Option> getOptions() {
return this.options;
}
public void setOptions(SortedSet<Option> options) {
this.options = options;
}
public boolean addOption(Option option) {
option.setTour(this);
return this.options.add(option);
}
public boolean removeOption(Option option) {
option.setTour(null);
return this.options.remove(option);
}
@OneToMany(mappedBy="tour",fetch=FetchType.LAZY)
@SortNatural
@OnDelete(action=OnDeleteAction.CASCADE)
@Cascade({CascadeType.PERSIST, CascadeType.MERGE, CascadeType.SAVE_UPDATE})
public SortedSet<TourVariant> getVariants() {
return this.variants;
}
public void setVariants(SortedSet<TourVariant> variants) {
this.variants = variants;
}
public boolean addVariant(TourVariant variant) {
variant.setTour(this);
return this.variants.add(variant);
}
public boolean removeVariant(TourVariant variant) {
variant.setTour(null);
return this.variants.remove(variant);
}
}
@Entity
@DiscriminatorValue(value="VARIANT")
public class TourVariant extends Product {
private Tour tour;
//some tour variant specific properties
@ManyToOne
@JoinColumn(name = "variant_tour_id") // <- Any way to make this work with the same join column, e.g. tour_id?
public Tour getTour() {
return this.tour;
}
public void setTour(Tour tour) {
this.tour = tour;
}
}
@Entity
@DiscriminatorValue(value="OPTION")
public class Option extends Product {
private Tour tour;
//some option specific properties
@ManyToOne
@JoinColumn(name = "option_tour_id") // <- Any way to make this work with the same join column, e.g. tour_id?
public Tour getTour() {
return this.tour;
}
public void setTour(Tour tour) {
this.tour = tour;
}
}
如上所示,我们必须使用不同的variant_tour_id
和option_tour_id
列,到目前为止,我们还找不到能够允许我们使用相同联接列的解决方案,例如tour_id
将Option类和TourVariant类都加入其父级Tour。
可悲的是,当我们尝试访问关系tour.getVariants()
或tour.getOptions()
时,总是会导致Hibernate吐出假人。
org.hibernate.WrongClassException: Object [id=2] was not of the specified subclass [xyz.model.TestOption] : loaded object was of wrong class class xyz.model.TestVariant
鉴于需要这种关系回到其父级Tour的产品只能是TourVariant或Option,并且辨别器subclazz
可以清楚地识别每个产品,有什么方法可以做到这一点只能使用一个tour_id
连接列?