如何使用与休眠的 ManyToOne 关系将泛型类型用于超级 class
How to use generic types into a super class using a ManyToOne relationship with hibernate
我有一个通用 class 使用单个 table 继承和其他子 classes :
文件,主要class
文件夹扩展文件
卡扩展文件
抽象 FileLink 扩展文件:FileLink 抽象class 扩展文件
FolderLink 扩展了 FileLink 并由 Folder 组成。
CardLink扩展了FileLink,由Card组成。
在我的文件 class 中,我有一个具有 oneToMany 关系的文件集合,它可以包含任何类型的文件,因此文件夹或文件夹 links 或卡片 links .
@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;
}
一个文件夹可以有多个link。
@Entity
@DiscriminatorValue(File.FOLDER + "")
public class Folder extends File {
@OneToMany(mappedBy = "linkedFolder", fetch = FetchType.LAZY, targetEntity = FolderLink.class)
protected Set<FolderLink> folderLinks = new HashSet<>();
private Object folderAttribute;
}
卡片相同
@Entity
@DiscriminatorValue(File.CARD+ "")
public class Card extends File {
@OneToMany(mappedBy = "linkedCard", fetch = FetchType.LAZY, targetEntity = CardLink.class)
protected Set<CardLink> cardLinks = new HashSet<>();
private Object cardAttribute;
}
文件link class 表示一个 link 文件并且没有使用太多特定属性,只有父文件和文件 linked。
事实上,当我序列化我的子文件集合时,我希望我的 links(FolderLink 或 Cardlinks)到 return linked 文件属性值。
所以 Folderlink class 应该是 return Folder 属性值,CardLink 是 Card 属性值,FileLink 是 File 属性值。
我的实际模型是这样制作的:
@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();
}
}
因此,当 FolderLink 被序列化时,除了通过 FileLink class 在其父 class(文件)中声明的属性外,我还可以检索 linked 文件夹属性,相同对于卡片 link.
但我想做的是将 OneToMany 关系声明到 File 和 FileLink classes 中:
@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<>();
}
文件link class 不会再抽象了。
@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();
}
}
但是没用。当我创建一个 FolderLink 时,我知道 linked 文件是一个文件夹,但是如果我从超级 class 中检索它,我无法将它转换为文件夹,hibernate 告诉我他不能转换文件放入文件夹,这是正常的,因为文件不是文件夹。
有没有办法实现这个目标?我目前的实现对我来说足够方便,但如果我能做更多,那就太好了。
您正在寻找的是多态关联映射,正如您提到的
hibernate tell me he cannot cast a File into a Folder, and it's normal because a File is not a Folder.
您可以通过添加另一列作为类型控制来定义您期望的类型。
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;
}
}
我有一个通用 class 使用单个 table 继承和其他子 classes :
文件,主要class
文件夹扩展文件
卡扩展文件
抽象 FileLink 扩展文件:FileLink 抽象class 扩展文件
FolderLink 扩展了 FileLink 并由 Folder 组成。
CardLink扩展了FileLink,由Card组成。
在我的文件 class 中,我有一个具有 oneToMany 关系的文件集合,它可以包含任何类型的文件,因此文件夹或文件夹 links 或卡片 links .
@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;
}
一个文件夹可以有多个link。
@Entity
@DiscriminatorValue(File.FOLDER + "")
public class Folder extends File {
@OneToMany(mappedBy = "linkedFolder", fetch = FetchType.LAZY, targetEntity = FolderLink.class)
protected Set<FolderLink> folderLinks = new HashSet<>();
private Object folderAttribute;
}
卡片相同
@Entity
@DiscriminatorValue(File.CARD+ "")
public class Card extends File {
@OneToMany(mappedBy = "linkedCard", fetch = FetchType.LAZY, targetEntity = CardLink.class)
protected Set<CardLink> cardLinks = new HashSet<>();
private Object cardAttribute;
}
文件link class 表示一个 link 文件并且没有使用太多特定属性,只有父文件和文件 linked。
事实上,当我序列化我的子文件集合时,我希望我的 links(FolderLink 或 Cardlinks)到 return linked 文件属性值。
所以 Folderlink class 应该是 return Folder 属性值,CardLink 是 Card 属性值,FileLink 是 File 属性值。
我的实际模型是这样制作的:
@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();
}
}
因此,当 FolderLink 被序列化时,除了通过 FileLink class 在其父 class(文件)中声明的属性外,我还可以检索 linked 文件夹属性,相同对于卡片 link.
但我想做的是将 OneToMany 关系声明到 File 和 FileLink classes 中:
@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<>();
}
文件link class 不会再抽象了。
@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();
}
}
但是没用。当我创建一个 FolderLink 时,我知道 linked 文件是一个文件夹,但是如果我从超级 class 中检索它,我无法将它转换为文件夹,hibernate 告诉我他不能转换文件放入文件夹,这是正常的,因为文件不是文件夹。
有没有办法实现这个目标?我目前的实现对我来说足够方便,但如果我能做更多,那就太好了。
您正在寻找的是多态关联映射,正如您提到的
hibernate tell me he cannot cast a File into a Folder, and it's normal because a File is not a Folder.
您可以通过添加另一列作为类型控制来定义您期望的类型。
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;
}
}