Among others, I have the following tables (not showing non-relevant columns):
Code:
CREATE TABLE sources (
id SERIAL NOT NULL,
CONSTRAINT sources_pk
PRIMARY KEY (id));
CREATE TABLE notes (
id SERIAL NOT NULL,
source int4 NOT NULL,
CONSTRAINT notes_pk
PRIMARY KEY (id),
CONSTRAINT notes_uq
UNIQUE (id, source));
ALTER TABLE notes ADD CONSTRAINT notes_source_fk
FOREIGN KEY (source) REFERENCES sources (id) ON UPDATE RESTRICT ON DELETE RESTRICT;
CREATE TABLE pages (
id SERIAL NOT NULL,
source int4 NOT NULL,
CONSTRAINT pages_pk
PRIMARY KEY (id),
CONSTRAINT pages_id_source_uq
UNIQUE (id, source));
ALTER TABLE pages ADD CONSTRAINT pages_source_fk
FOREIGN KEY (source) REFERENCES sources (id) ON UPDATE RESTRICT ON DELETE RESTRICT;
CREATE TABLE note_fragments (
id SERIAL NOT NULL,
source int4 NOT NULL,
page int4 NOT NULL,
CONSTRAINT note_fragments_pk
PRIMARY KEY (id),
CONSTRAINT note_fragments_uq
UNIQUE (id, source));
ALTER TABLE note_fragments ADD CONSTRAINT note_fragments_source_page_fk
FOREIGN KEY (page, source) REFERENCES pages (id, source) ON UPDATE RESTRICT ON DELETE RESTRICT;
CREATE TABLE note_fragment_assignments (
id SERIAL NOT NULL,
note int4 NOT NULL,
note_source int4 NOT NULL,
fragment int4 NOT NULL,
fragment_source int4 NOT NULL,
CONSTRAINT note_fragment_assignments_pk
PRIMARY KEY (id),
CONSTRAINT note_fragment_assignments_ck
CHECK (note_source = fragment_source));
ALTER TABLE note_fragment_assignments ADD CONSTRAINT note_fragment_assignments_note_note_source_fk FOREIGN KEY (note, note_source) REFERENCES notes (id, source) ON UPDATE RESTRICT ON DELETE RESTRICT;
ALTER TABLE note_fragment_assignments ADD CONSTRAINT note_fragment_assignments_fragment_fragment_source_fk FOREIGN KEY (fragment, fragment_source) REFERENCES note_fragments (id, source) ON UPDATE RESTRICT ON DELETE RESTRICT;
The business logic behind these tables is as following:
- A source is a set of pages.
- A source contains notes.
- Notes are made of fragments (which are placed on pages). Note-to-fragment relation is n:m. It is prohibited to form one note out of fragments from different sources.
I know that maybe the design is not beautiful and the source column is redundant, but I have found no other solution to maintain the integrity without writing explicit triggers.
When trying to implement the Java code, I have prepared, i.a., the following entity classes:
Source.javaCode:
@Entity
@Table(name = "sources")
public class Source implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "id")
private Integer id;
@OneToMany(mappedBy = "source")
private Collection<Note> noteBySourceCollection;
@OneToMany(mappedBy = "source")
private Collection<Page> pageBySourceCollection;
// getters, setters etc.
}
Note.javaCode:
@Entity
@Table(name = "notes")
public class Note implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "id")
private Integer id;
@JoinColumn(name = "source", referencedColumnName = "id")
@ManyToOne(optional = false)
private Source source;
@OneToMany(mappedBy = "note")
private Collection<NoteFragmentAssignment> noteFragmentAssignmentByNoteCollection;
// getters, setters etc.
}
Page.javaCode:
@Entity
@Table(name = "pages")
public class Page implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "id")
private Integer id;
@JoinColumn(name = "source", referencedColumnName = "id")
@ManyToOne(optional = false)
private Source source;
@OneToMany(mappedBy = "page")
private Collection<NoteFragment> noteFragmentByPageCollection;
// getters, setters etc.
}
NoteFragment.javaCode:
@Entity
@Table(name = "note_fragments")
public class NoteFragment implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "id")
private Integer id;
@JoinColumns({
@JoinColumn(name = "page", referencedColumnName = "id"),
@JoinColumn(name = "source", referencedColumnName = "source")
})
@ManyToOne(optional = false)
private Page page;
@OneToMany(mappedBy = "fragment")
private Collection<NoteFragmentAssignment> noteFragmentAssignmentByFragmentCollection;
// getters, setters etc.
}
NoteFragmentAssignment.javaCode:
@Entity
@Table(name = "note_fragment_assignments")
public class NoteFragmentAssignment implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "id")
private Integer id;
@JoinColumns({
@JoinColumn(name = "note", referencedColumnName = "id"),
@JoinColumn(name = "note_source", referencedColumnName = "source")
})
@ManyToOne(optional = false)
private Note note;
@JoinColumns({
@JoinColumn(name = "fragment", referencedColumnName = "id"),
@JoinColumn(name = "fragment_source", referencedColumnName = "source")
})
@ManyToOne(optional = false)
private NoteFragment fragment;
// getters, setters etc.
}
On runtime, the Configuration.buildSessionFactory() method fails with the following exception:
Code:
org.hibernate.MappingException: Unable to find column with logical name: source in pages
at org.hibernate.cfg.Ejb3JoinColumn.checkReferencedColumnsType(Ejb3JoinColumn.java:587)
at org.hibernate.cfg.BinderHelper.createSyntheticPropertyReference(BinderHelper.java:258)
at org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.java:116)
at org.hibernate.cfg.Configuration.processEndOfQueue(Configuration.java:1596)
at org.hibernate.cfg.Configuration.processFkSecondPassInOrder(Configuration.java:1519)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1420)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1844)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1928)
at [...]
The exception is rewritten by Ejb3JoinColumn.checkReferencedColumnsType() from the exception thrown by Configuration$MappingsImpl.getPhysicalColumnName(). Indeed, Configuration.columnNameBindingPerTable entries don't contain the foreign keys (only the basic columns).
Is there a way to "cascade" the foreign keys in Hibernate? I am using Hibernate 4.3.4.Final.