Reputation: 2359
I'm trying to model one entity A as append-only, with another child entity that references the first. So A has a structure like (sorted by inserted_at DESC
):
| id | version | column | inserted_at |
|------|-----------+---------|-------------|
| 5 | 2 | "baz" | 2020-04-20 |
| 3 | 2 | "zoot" | 2020-04-20 |
| 3 | 1 | "bar " | 2020-04-18 |
| 5 | 1 | "foo" | 2020-04-10 |
(id, version)
forms the primary key for A (One could do (id, inserted_at)
as well, but the developer decided version numbers were more readable).
Now B belongs to A, and each B will correspond with exactly one (id, version)
pair of A. So something like:
| id | a_id | a_version | column | inserted_at |
|------|-------+-----------+---------+-------------|
| 4 | 5 | 2 | "pigs" | 2020-05-05 |
| 3 | 5 | 2 | "goats"| 2020-05-03 |
| 2 | 5 | 1 | "rams" | 2020-05-02 |
| 1 | 3 | 1 | "bears"| 2020-04-18 |
my question is, how can I model these with Ecto Schemas? I think I know from reading docs what the A schema looks like, except for the has_many
:
defmodule MyASchema do
use Ecto.Schema
@primary_key false
schema "table_a" do
field :id, :id, primary_key: true
field :version, :integer, primary_key: true
field :column, :string
field :inserted_at, :utc_datetime
has_many :bs, MyBSchema # what goes here for :foreign_key?
end
end
But the B schema (especially belongs_to
) is less clear to me:
defmodule MyBSchema do
use Ecto.Schema
@primary_key
schema "table_b" do
field :id, :id, primary_key: true
field :column, :string
field :inserted_at, :utc_datetime
# how does belongs_to work here? would it be
#
# belongs_to :a, MyASchema, primary_key: [:id, :version]
#
# or
#
# belongs_to :a, MyASchema, define_key: false
# field :a_id, :id
# field :a_version, :integer
#
# ? If so, how could I query such that the :a field of the
# struct is populated?
end
end
Happy to clarify further, thanks for reading + any help 🙂
Upvotes: 1
Views: 2832
Reputation: 9558
According to the Elixir forum, Ecto does not support compound foreign keys when working with associations.
One solution would be to add a "regular" unique primary key (e.g. an auto-incrementing integer or UUID) and base the references off of that id. Sometimes you make consolations when working with database abstraction layers because relationships are easier to define when the database has a simple one-column primary key (i.e. not a composite).
If altering the database schema is not possible, then you would need to manually resolve the associations in your code. You may need to set up multiple transactions as outlined by this post.
Upvotes: 2