For a multi tenancy eCommerce application, I have given the following ER schema:
Order has_many OrderProduct belongs_to Product belongs_to Price
With Ecto, it would be easy to insert an Order with many OrderProduct at once via cast_assoc(:order_product)
in the changeset function of Order.
But since a Product and also a Price may be deleted in the future, I would like to additionally store the value of Price and a quantity in OrderProducts (:price
, :quantity
).
As far is I know I would have the following options to do that:
- In the changeset function of OrderProduct I could fetch Product and join Price by the ID of Product and add
:price
of Price as change to OrderProduct. This would result in N+1 queries, since I have to execute that query for every OrderProduct in Order (which would be ok in this case since I have only a limited number of Products per Order). But furthermore, I would prefer keeping out the Repo of the schema definition module. But most importantly: I am using different schemas in my multi tenancy setup so I need to know theprefix
in the changeset function of OrderProduct to execute the query on the correctprefix
. - Iterate OrderProducts outside of the schema definitions in my
Orders
module and add:price
as change to OrderProduct changeset:
%Order{}
|> Order.changeset(attrs)
|> iterate_order_products_and_map_price_change(tenant)
|> Repo.insert(prefix: tenant)
- Use
Ecto.Multi
where the order is inserted first and then I add the relationships with an extraEcto.Multi.run
I would prefer the first option since it seems to me that this would be the cleanest approach to do that.
- Are there any other or better options for this scenario?
- Would it be possible to preload via join Product and Price for OrderProduct on an insert outside of the schema as well? Then I wouldn't have the
N+1
in 1.?