I am experimenting with database referential integrity and I have some doubts. I have a design that uses composite keys and it has referential integrity but I find that composite keys may be difficult to deal with at the app level.
The following tables are a simplification, I have tables with 4 and 5 columns as a composite key. There is full referential integrity, it's a fortress, and it makes a lot of academic sense, but as a pragmatic programmer I am thinking this is going to be a rabbit hole at the app level. So I was wondering how would the schema look like with surrogate keys while still maintaining referential integrity, if such a thing is possible.
The simplified schema using composite keys look like this:
CREATE TABLE organisations (
id integer NOT NULL,
name character varying NOT NULL
);
ALTER TABLE ONLY organisations ADD CONSTRAINT organisations_pkey PRIMARY KEY (id);
CREATE TABLE invoice_series (
natural_key varying NOT NULL,
organisation_id integer NOT NULL
);
ALTER TABLE ONLY invoice_series ADD CONSTRAINT invoice_series_pkey PRIMARY KEY (organisation_id, natural_key);
CREATE TABLE spaces (
natural_key integer NOT NULL,
organisation_id integer NOT NULL
invoice_serie_id integer NOT NULL
);
ALTER TABLE ONLY spaces ADD CONSTRAINT spaces_pkey PRIMARY KEY (organisation_id, natural_key);
ALTER TABLE ONLY spaces ADD CONSTRAINT fk_spaces_org FOREIGN KEY (organisation_id, natural_key) REFERENCES invoice_series
The simplified schema without composite keys looks like this:
CREATE TABLE organisations (
id integer NOT NULL,
name character varying NOT NULL
);
CREATE TABLE invoice_series (
id integer NOT NULL,
organisation_id integer NOT NULL,
);
CREATE TABLE spaces (
id integer NOT NULL,
organisation_id integer NOT NULL
invoice_serie_id integer NOT NULL
);
I could do this:
execute "ALTER TABLE spaces ADD CONSTRAINT fk_rails_invoice_serie_spaces FOREIGN KEY (organisation_id, invoice_serie_id) REFERENCES invoice_series;"
But that will force me to add an unique index on invoice_series with :organisation_id and :id. Which seems a really weird index to me.
What would be a better approach?
--
An organisation may have 0 or more Spaces A space belongs to one organisation
An organisation has 1 or many Invoice Series An invoice series belongs to one organisation
A space has one Invoice Serie An Invoice Serie may belong to 0 or more spaces.
Given these tables how do I ensure referential integrity, so that a space can only be associated with an invoice serie belonging to the same organisation?