1

これはかなり簡単なように思えますが、エレガントな解決策を思い付くのに苦労しています。

FileFolderという 2 つの hibernate アノテーションが付けられたクラスで構成される基本的なファイル システムの例を使用してみましょう。

2 つのクラスの共通プロパティをFileSystemObjectインターフェイスに抽象化します。

public interface FileSystemObject {
    public String getName();
    public URI getWhere();
}

そして2つのクラス:

ファイル:

@Entity
@Table(name = "FILE")
public class File implements FileSystemObject, Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "FILE_ID")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Column(name = "NAME", nullable = false)
    @Index(name = "FILE_NAME", columnNames={"NAME"})
    private String name;

    @Column(nullable = false)
    private URI where;

    public File() {}

    public File(String name, URI where) {
        this.name = name;
        this.where = where;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public URI getWhere() {
        return where;
    }

    public void setWhere(URI where) {
        this.where = where;
    }
}

フォルダ:

@Entity
@Table(name = "FOLDER")
public class Folder implements FileSystemObject, Serializable {

    private static final long serialVersionUID = 2L;

    @Id
    @Column(name = "FOLDER_ID")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Column(name = "NAME", nullable = false)
    @Index(name = "FOLDER_NAME", columnNames={"NAME"})
    private String name;

    @Column(nullable = false)
    private URI where;

    @CollectionOfElements
    @JoinTable(name = "FOLDER_CONTENTS",
               joinColumns = @JoinColumn(name = "FOLDER_ID"))
    private List<FileSystemObject> contents;

    public Folder() {}

    public Folder(String name, URI where, List<FileSystemObject> contents) {
        this.name = name;
        this.where = where;
        this.contents = contents;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public URI getWhere() {
        return where;
    }

    public void setWhere(URI where) {
        this.where = where;
    }

    public List<FileSystemObject> getContents() {
        return contents;
    }

    public void setContents(List<FileSystemObject> contents) {
        this.contents = contents;
    }
}

論理的には、FolderのコンテンツはFileまたはFolderである可能性があるため、List のコンテンツがFileSystemObject型であることが理にかなっています。

ここで、pom.xml 内ですべてが正しく設定されていると仮定して、スキーマを生成しようとすると、次のようになります。

mvn hibernate3:hbm2ddl

次のエラーがスローされます。

Failed to execute goal org.codehaus.mojo:hibernate3-maven-plugin:2.0:hbm2ddl (generate-ddl) on
project foo: Execution generate-ddl of goal org.codehaus.mojo:hibernate3-maven
plugin:2.0:hbm2ddl failed: Could not determine type for: com.foo.data.FileSystemObject, for
columns: [org.hibernate.mapping.Column(element)] -> [Help 1]

うまくいけば、誰かがこれに光を当てることができます!

4

1 に答える 1

1

タイプがインターフェイスである可能性はありますが、エンティティを構成した方法では機能しません。両方のエンティティ タイプを同じコレクションに組み合わせるには、それ自体がエンティティである共通のスーパータイプを共有する必要があります。(つまり、そのレベルで ID を定義する、両方が継承する共通のスーパークラスである FileSystemObject のようなものが必要です。)

問題は、次のクエリを検討することです。

select c from Folder f, f.contents c where f.name = 'FOLDER' and c.id = 3;

ID 3 を持つフォルダーとファイルの両方が存在する場合、どのようにして必要なものを知ることができるのでしょうか? これが、同じコレクションにある場合、共通のスーパークラスを共有する必要がある理由です。

于 2012-10-10T01:35:22.003 に答える