如何使用与休眠的 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;
    }
}