I have entities Workflows
, Steps
and Fields
. They relate to each other like this:
- A
Workflow
has manySteps
andFields
. - A
Step
has manyFields
.
A Field
can belong to either a Workflow
or a Step
but not to both at once. My first option is to add two foreign key columns to Field
where one will always be null
. So the fields table will have the following columns:
Fields
- id
- name
- step_id (FK to steps)
- workflow_id (FK to workflows)
This allows to enforce uniqueness of the name in the scope of the parent (by creating a unique index on the parent ID and the name) as well as use foreign key cascading deletes ensuring any time a Workflow
or Step
is deleted the related Fields
will be deleted as well. However, one column is always null
and if I introduce another parent of Field
in the future it would require adding yet another FK column.
In an attempt to normalize this, I can set up join tables and express the relationship in another way:
Fields
- id
- name
WorkflowFields
- workflow_id (FK to workflows)
- field_id (FK to fields)
StepFields
- step_id (FK to steps)
- field_id (FK to fields)
Now I don't have any null values but I lose the ability to enforce uniqueness and cascade the deletes (when a Workflow
or Step
is deleted, the join record WorkflowField
or StepField
will be deleted but not the actual Field
record itself).
How do I handle the uniqueness requirement? Should
name
be a column on the join table instead of thefields
table? This feels wrong but I don't see another way.How do I handle cascading deletes? I want the corresponding
Field
to be deleted any time theWorkflow
orStep
or any of the join models are deleted. Are database triggers my only option here?Is there a better alternative or are these the options I'm limited to?