如何将具有休眠状态的ManyToOne关系的泛型类型用于超类

时间:2020-07-18 18:34:40

标签: java hibernate jpa data-modeling hibernate-onetomany

我有一个使用单表继承的泛型类和其他子类:

文件,主要类

文件夹扩展文件

卡扩展文件

抽象FileLink扩展File:一个扩展File的FileLink抽象类

FolderLink扩展FileLink并由一个Folder组成。

CardLink扩展了FileLink并由Card组成。

在我的File类中,我具有一个具有oneToMany关系的文件集合,该文件集合可以包含任何类型的File,因此包含文件夹或文件夹链接或卡链接。

@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;
}

一个文件夹可以具有多个链接。

@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;
}

Filelink类表示到文件的链接,没有使用太多特定的属性,只是父文件和链接的文件。

实际上,当我序列化子文件集合时,我希望我的链接(FolderLink或Cardlinks)返回链接文件的属性值。

因此,Folderlink类应该返回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序列化时,除了通过卡链接链接在其父类(文件)中声明的属性之外,我还可以检索链接的文件夹属性。

但是我想做的是仅在File和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<>();

}

Filelink类不再是抽象的。

@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时,我知道链接的文件是一个Folder,但是如果我从超类检索到该文件,则无法将其转换为Folder,休眠状态告诉我他不能将文件转换为Folder,这是正常的,因为文件不是文件夹。

有没有办法实现这个目标?我目前的实现方式对我来说足够方便,但是如果我能做更多的话,那就太好了。

1 个答案:

答案 0 :(得分:2)

您正在寻找的是您提到的多态关联映射

休眠告诉我他不能将文件投射到文件夹中,这很正常,因为文件不是文件夹。

您可以通过添加另一列作为类型​​控件来定义所需的类型。

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;
    }
}