Java 如何使用与hibernate的多通关系将泛型类型用于超类
我有一个使用单表继承和其他子类的泛型类: 文件,主类 文件夹扩展文件 卡扩展文件 抽象文件链接扩展文件:一个文件链接抽象类扩展文件 FolderLink扩展了FileLink并由一个文件夹组成 CardLink扩展了FileLink并由一张卡组成 在我的File类中,我有一个具有oneToMany关系的文件集合,它可以包含任何类型的文件,例如文件夹、文件夹链接或卡片链接Java 如何使用与hibernate的多通关系将泛型类型用于超类,java,hibernate,jpa,data-modeling,hibernate-onetomany,Java,Hibernate,Jpa,Data Modeling,Hibernate Onetomany,我有一个使用单表继承和其他子类的泛型类: 文件,主类 文件夹扩展文件 卡扩展文件 抽象文件链接扩展文件:一个文件链接抽象类扩展文件 FolderLink扩展了FileLink并由一个文件夹组成 CardLink扩展了FileLink并由一张卡组成 在我的File类中,我有一个具有oneToMany关系的文件集合,它可以包含任何类型的文件,例如文件夹、文件夹链接或卡片链接 @DiscriminatorColumn(name = "file_type", discriminato
@DiscriminatorColumn(name = "file_type", discriminatorType = DiscriminatorType.INTEGER)
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class File{
@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
List<File> subFiles = new Linkedlist()
@ManyToOne(fetch = FetchType.LAZY)
protected File parent;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(length= 40)
private String name;
@Lob
private String description;
}
因此,当一个FolderLink被序列化时,除了通过FileLink类在其父类(文件)中声明的属性外,我还可以检索链接的文件夹属性,对于卡片链接也是如此
但我想做的是在文件和FileLink类中声明OneToMany关系:
@DiscriminatorColumn(name = "file_type", discriminatorType = DiscriminatorType.INTEGER)
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class File{
@OneToMany(mappedBy = "linkedFile", fetch = FetchType.LAZY, targetEntity = FileLink.class)
protected Set<FileLink> fileLinks = new HashSet<>();
}
但它不起作用。当我创建FolderLink时,我知道链接的文件是一个文件夹,但如果我从超类检索它,我无法将其转换为文件夹,hibernate告诉我他无法将文件转换为文件夹,这是正常的,因为文件不是文件夹
有没有办法实现这个目标?我目前的实现对我来说很方便,但如果我能做得更多,那就太好了。正如您所提到的,您正在寻找的是多态关联映射 hibernate告诉我他不能将文件强制转换到文件夹中,这很正常,因为文件不是文件夹 可以通过添加另一列作为类型控件来定义所需的类型
package com.example;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.Column;
import org.hibernate.annotations.Any;
import org.hibernate.annotations.AnyMetaDef;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.MetaValue;
@Entity
@DiscriminatorValue(File.FILE_LINK + "")
public class FileLink extends File {
@Any (
metaColumn = @Column(name = "linkedFileType"),
fetch=FetchType.LAZY
)
@AnyMetaDef(idType = "long", metaType = "string", metaValues = {
@MetaValue(targetEntity = Folder.class, value = "folder"),
@MetaValue(targetEntity = Card.class, value = "card")
})
@Cascade({org.hibernate.annotations.CascadeType.ALL})
@JoinColumn(name = "file_linked_id")
protected File linkedFile;
@Override
public String getName() {
return "Link to "+this.getLinkedFile().getName();
}
...
@JsonIgnore
public File getLinkedFile(){
return this.linkedfile;
}
}
在设计继承层次结构时,无论何时键入
B扩展A
,您都应该问自己这样一个问题:“B
可以在需要A
的地方使用吗?”。从这个角度来看,FolderLink
是多余的,因为您可以将文件夹
分配给FileLink.linkedFile
(因为文件夹
扩展了文件
)。另外,文件夹
从文件
继承文件链接
属性@crizzis是的,但是linkedFile链接一个文件,因此如果我序列化一个文件链接,我只能获取文件属性,而不能获取文件夹属性,这就是为什么我需要一个FolderLink类来这样做。我想序列化FolderLink或CardLink(卡片扩展文件也有自己的属性),就像它是文件夹或卡片一样。在这种情况下,您可能只需要一个轻量级的界面来表达FolderLink
和Folder
(即PhysicalFolder实现文件夹
和FolderLink实现文件夹
;不确定命名),不需要继承。请注意,在您的设置中,FolderLink
继承它从不使用的文件夹的物理属性,因为getter委托给linkedFolder
和FileLink
都可以从文件继承,或者更好的是,从父超链接继承lass(例如,AbstractFilesystemItem
)不声明不需要的物理属性FolderLink不会从文件夹继承属性,它不是文件夹,而是文件,它由文件夹组成。是的,文件夹和FolderLink应该共享同一个接口,但这不是问题所在(实际上Jackson只需要相同的属性名称…)***链接类从文件继承,因为我使用单表继承类型。感谢您的帮助,它工作得很好。我不明白的是,我不必创建任何“linkedFileType”列,但它似乎没有。您的配置中的hibernate.hbm2ddl模式是什么?我猜它会自动更新您的表。嗯,ddl auto处于更新模式,但尚未创建列,并且在没有列的情况下运行良好,这非常奇怪。经过几次测试后,似乎这些注释@Any etc甚至都不是必需的,因为在我的文件类中,我已经为文件的不同子类使用了鉴别器值。因此,如果将linkedFile声明为文件,hibernate可以使用ri填充它ght子类。我不知道它以前为什么不起作用,真是个大谜团!
@NoArgsConstructor
public abstract class FileLink extends File {
@Override
public String getName() {
return "Link to "+this.getLinkedFile().getName();
}
@Override
public String getDescription() {
return this.getLinkedFile().getDescription();
}
...
@JsonIgnore
public abstract File getLinkedFile();
}
@Entity
@DiscriminatorValue(File.FOLDER_LINK + "")
public class FolderLink extends FileLink {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "folder_linked_id", insertable = false, updatable = false)
protected Folder linkedFolder;
@JsonIgnore
public File getLinkedFolder() {
return this.linkedFolder;
}
@Override
public String getFolderAttribute() {
return "Link to "+this.getLinkedFile().getFolderAttribute();
}
@Override
public File getLinkedFile() {
return this.getLinkedFolder();
}
}
@Entity
@DiscriminatorValue(File.CARD_LINK + "")
public class CardLink extends FileLink {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "card_linked_id", insertable = false, updatable = false)
protected Card linkedCard;
@JsonIgnore
public File getLinkedCard() {
return this.linkedCard;
}
@Override
public String getCardAttribute() {
return "Link to "+this.getLinkedFile().getCardAttribute();
}
@Override
public File getLinkedFile() {
return this.getLinkedCard();
}
}
@DiscriminatorColumn(name = "file_type", discriminatorType = DiscriminatorType.INTEGER)
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class File{
@OneToMany(mappedBy = "linkedFile", fetch = FetchType.LAZY, targetEntity = FileLink.class)
protected Set<FileLink> fileLinks = new HashSet<>();
}
@NoArgsConstructor
@Entity
@DiscriminatorValue(File.FILE_LINK + "")
public class FileLink extends File {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "file_linked_id", insertable = false, updatable = false)
protected File linkedFile;
@Override
public String getName() {
return "Link to "+this.getLinkedFile().getName();
}
...
@JsonIgnore
public File getLinkedFile(){
return this.linkedfile;
}
}
@Entity
@DiscriminatorValue(File.FOLDER_LINK + "")
public class FolderLink extends FileLink {
@Override
public String getFolderAttribute() {
return "Link to "+((Folder)this.getLinkedFile()).getFolderAttribute();
}
}
@Entity
@DiscriminatorValue(File.CARD_LINK + "")
public class CardLink extends FileLink {
@Override
public String getCardrAttribute() {
return "Link to "+((Card)this.getLinkedFile()).getCardAttribute();
}
}
package com.example;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.Column;
import org.hibernate.annotations.Any;
import org.hibernate.annotations.AnyMetaDef;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.MetaValue;
@Entity
@DiscriminatorValue(File.FILE_LINK + "")
public class FileLink extends File {
@Any (
metaColumn = @Column(name = "linkedFileType"),
fetch=FetchType.LAZY
)
@AnyMetaDef(idType = "long", metaType = "string", metaValues = {
@MetaValue(targetEntity = Folder.class, value = "folder"),
@MetaValue(targetEntity = Card.class, value = "card")
})
@Cascade({org.hibernate.annotations.CascadeType.ALL})
@JoinColumn(name = "file_linked_id")
protected File linkedFile;
@Override
public String getName() {
return "Link to "+this.getLinkedFile().getName();
}
...
@JsonIgnore
public File getLinkedFile(){
return this.linkedfile;
}
}