Mapping: Table contains physical column name referred to by multiple logical column names

Viewed 1984

I have 3 classes - Issue, Sprint and EmbeddableId class SprintId.

I don't know how to achieve having jiraInstance field both in Issue and Sprint class. As Issue may not be connected to any Sprint I want to have jiraInstance java field on Issue to track in which jira instance this particular issue was created. When its connected to Sprint I want to just have jiraInstance as part of its composite key. But below mapping gives me:

Caused by: org.hibernate.DuplicateMappingException: Table [issue] contains physical column name [jira_instance] referred to by multiple logical column names: [jira_instance], [jiraInstance]

classes:

class Issue {
    @ManyToOne()
    @JoinColumns({
            @JoinColumn(
                    name = "sprint_id",
                    referencedColumnName = "sprint_id"),
            @JoinColumn(
                    name = "jira_instance",
                    referencedColumnName = "jira_instance")
    })
    private Sprint lastSprint;

    //this field causes clash with 'jira_instance' in @JoinColumn
    private String jiraInstance;
}

class Sprint {
    @EmbeddedId
    private SprintId id;
}
class SprintId implements Serializable {

    @Column(name = "sprint_id")
    private String sprintId;

    @Column(name = "jira_instance")
    private String jiraInstance;
}

Adding @Column as:

@Column(name="jira_instance")
private String jiraInstance;

cause hibernate to claim that it has to be insertable = true, updatable = false, but I need to be able to add jiraInstance to Issue when its not connected to any sprint.

2 Answers

To clarify - as there is no marked answer to this issue yet:

When you use a named column reference in any way on one class field, make sure ALL references use the exact same name. Especially when they are differently named (jira_instance vs. jiraInstance, in your example).

The following example should work:

class Issue {
    @ManyToOne()
    @JoinColumns({
            @JoinColumn(
                    name = "sprint_id",
                    referencedColumnName = "sprint_id"),
            @JoinColumn(
                    name = "jira_instance",
                    referencedColumnName = "jira_instance") // make sure you use the same name
    })
    private Sprint lastSprint;

    @Column(name = "jira_instance") // make sure you use the same name
    private String jiraInstance;
}

class Sprint {
    @EmbeddedId
    private SprintId id;
}
class SprintId implements Serializable {

    @Column(name = "sprint_id")
    private String sprintId;

    @Column(name = "jira_instance") // make sure you use the same name
    private String jiraInstance;
}

This means: insertable = false, updatable = false is not necessary to solve this issue.

You have to understand that only one property/field can be used for writing a column, otherwise there could be conflicts. Use the following mapping:

class Issue {
    @ManyToOne()
    @JoinColumns({
            @JoinColumn(
                    name = "sprint_id",
                    referencedColumnName = "sprint_id"),
            @JoinColumn(
                    name = "jira_instance",
                    referencedColumnName = "jira_instance", insertable = false, updatable = false)
    })
    private Sprint lastSprint;

    private String jiraInstance;
}

You just have to make sure that when you set lastSprint, you also set jiraInstance to the value of Sprint#jiraInstance

Related