wener
wener

Reputation: 7760

Save same column in JPA SecondaryTable with N:1 relationship

My code look like this:

@Data
@Accessors(chain = true, fluent = true)
@Entity
@Table(name = "T_FILE_META", indexes = {@Index(columnList = "filename")}
)
@SecondaryTable(name = "T_FILE_META_SHA",
        pkJoinColumns = @PrimaryKeyJoinColumn(name = "sha1", referencedColumnName = "sha1")
        , indexes = {@Index(columnList = "sha1", unique = true), @Index(columnList = "md5", unique = true)}
)
public class FileMeta
{
    @Id
    @GeneratedValue
    private Long id;

    private String filename;

    @Column(length = 40, table = "T_FILE_META_SHA")
    private String type;
    @Column(length = 40, table = "T_FILE_META_SHA")
    private String sha1;
    @Column(length = 32, table = "T_FILE_META_SHA")
    private String md5;
}

I want two table: T_FILE_META,T_FILE_META_SHA,The relationship is N:1

T_FILE_META( pk(id),filename, fk(sha1))
T_FILE_META_SHA( pk(sha1), md5, type)

Use this code will get Unable to find column with logical name: sha1 in org.hibernate.mapping.Table(t_file_meta) and its related supertables and secondary tables

About the SecondaryTable I learn from wiki:Tables#Multiple_tables.

How to define this entity ? BTW, T_FILE_META_SHA only cascade update.

EDITED

So,SecondaryTable is only for 1:1,I changed the entity to

/**
 * Different filename can reference to a same file meta
 */
@Data
@Accessors(chain = true, fluent = true)
@Entity
@Table(name = "T_FILE_REF",
        indexes = {@Index(columnList = "filename"), @Index(columnList = "owner")}
)
public class FileReference
{
    @Id
    @GeneratedValue
    private Long id;

    private String filename;
    private String owner;

    /**
     * The sha1 reference may change
     * <p/>
     * This field only used for FK
     */
    @Setter(AccessLevel.NONE)
    @Getter(AccessLevel.NONE)
    private String sha1;
    @Column(columnDefinition = "default now()")
    private Date lastModificationDate;
    @Column(columnDefinition = "default now()")
    private Date uploadDate;


    @Getter(AccessLevel.NONE)
    @ManyToOne(cascade = CascadeType.PERSIST, optional = false)
    @JoinColumn(name = "sha1",
            referencedColumnName = "sha1",
            updatable = false,
            nullable = false)
    private FileMeta meta;


    public FileMeta meta()
    {
        if (meta == null)
        {
            meta = new FileMeta();
        }
        return meta;
    }

    public String md5()
    {
        return meta().md5();
    }

    public String type()
    {
        return meta().type();
    }

    public String sha1()
    {
        return meta().sha1();
    }


    @Data
    @Accessors(chain = true, fluent = true)
    @Entity
    @Table(name = "T_FILE_META", indexes = {@Index(columnList = "md5")})
    public static class FileMeta
    {
        @Id
        @Column(length = 40,
                unique = true,
                updatable = false,
                nullable = false)
        private String sha1;

        @Column(length = 32, updatable = false, nullable = false)
        private String md5;

        /**
         * File size
         */
        @Column(precision = 32, nullable = false)
        private Long length;

        /**
         * Mime type
         */
        @Column(length = 40)
        private String type;
    }
}

This looks like more sensible,REF:META is N:1.REF delegate some field of META.But is this ok ? FileMeta is not updateable.

When I change the sha1 of Reference, is it possible to auto load the FileMeta if exists ?

Upvotes: 1

Views: 1489

Answers (1)

Vlad Mihalcea
Vlad Mihalcea

Reputation: 154000

The @SecondaryTable allows you to join two tables together in a one-to-one relation, as if you have split the same row into two separate tables.

For a one-to-many relation, you need to use a @OneToMany association instead.

The problem with your mapping is that you specified a joining column that doesn't exist in the T_FILE_META table:

pkJoinColumns = @PrimaryKeyJoinColumn(name = "sha1", referencedColumnName = "sha1")
  • name: refers to a T_FILE_META column (which doesn't exist)
  • referencedColumnName: refers to a T_FILE_META_SHA column

So, you need to add the two sha1 fields to the FileMeta entity:

@Column(name = "sha1")
private String sha1Fk;

@Column(name = "sha1", table = "T_FILE_META_SHA")
private String sha1Pk;

Upvotes: 1

Related Questions