starnowski / posmulten-hibernate

Integration of Posmulten and Hibernate libraries
GNU Lesser General Public License v2.1
3 stars 0 forks source link

Add functionality that optionaly creates foreignKey constraint for OneToOne and OneToMany relation that use JoinColumnsOrFormulas annotation #17

Open starnowski opened 2 years ago

starnowski commented 2 years ago

Hibernate does not allow for overlapping foreign keys https://hibernate.atlassian.net/browse/HHH-6221. Because of this issue it is harder to generate database schema where foreign keys shares tenant id column with primary key and other foreign keys. For below example we have two tables: The user_info_nonforeignkeyconstraint table can have multiple references to posts table.


create table user_info_nonforeignkeyconstraint (
       user_id varchar(255) not null,
        tenant varchar(255) not null,
        password varchar(255),
        username varchar(255),
        primary key (user_id, tenant)
    )

create table posts_nonforeignkeyconstraint (
       key int8 not null,
        tenant_id varchar(255) not null,
        text text,
        user_id varchar(255),
        primary key (key, tenant_id)
    )

To map these tables into java model and having issue "Mixing insertable and non insertable columns in a property is not allowed" we need to use JoinColumnsOrFormulas annotation.


@Table(name = "user_info_nonforeignkeyconstraint")
@ToString(of = {"primaryKey", "username"})

public class User {

    @EmbeddedId
    @AttributeOverride(name = "stringKey", column = @Column(name = "user_id"))
    @AttributeOverride(name = "tenant", column = @Column(name = "tenant", insertable = false, updatable = false))
    private StringPrimaryKey primaryKey;
    private String username;
    private String password;

    @OneToMany(mappedBy = "author", fetch = LAZY)
    @JoinColumnsOrFormulas(value = {
            //name --> Post column, referencedColumnName -- User column
            @JoinColumnOrFormula(column = @JoinColumn(name = "tenant_id", referencedColumnName = "tenant")),
            @JoinColumnOrFormula(column = @JoinColumn(name = "user_id", referencedColumnName = "user_id"))
    })
    private Set<Post> posts;
}

@Table(name = "posts_nonforeignkeyconstraint")
@IdClass(LongPrimaryKey.class)

public class Post {

    @Id
    @GeneratedValue
    private long key;
    @Id
    @Column(name = "tenant_id", insertable = false, updatable = false)
    private String tenant;

    @ManyToOne
    @JoinColumnsOrFormulas(value = {
            @JoinColumnOrFormula(formula = @JoinFormula(value = "tenant_id", referencedColumnName = "tenant")),
            @JoinColumnOrFormula(column = @JoinColumn(name = "user_id", referencedColumnName = "user_id"))
    })
    private User author;

    @Column(columnDefinition = "text")
    private String text;
}

@Embeddable

public class StringPrimaryKey implements Serializable {

    private String stringKey;

    private String tenant;

//Setters, Getters, equals and hashCode

The problem with this approach is that Hibernate does not generate foreign key in posts_nonforeignkeyconstraint to user_info_nonforeignkeyconstraint table. Developer needs to for test purpose add this statement in import.sql file.


ALTER TABLE posts_nonforeignkeyconstraint ADD CONSTRAINT fk_posts_users_author_manual_added FOREIGN KEY (user_id, tenant_id) REFERENCES user_info_nonforeignkeyconstraint;

The goal is to add feature that will lookup for such *annotation combination (activated by a property) or with specified annotation for property and generate foreign key based on tenant column and column that reference to other table.

Blocked by: https://github.com/starnowski/posmulten/issues/252

starnowski commented 1 year ago

Consider adding two annotations: