Home > Net >  Is it a good idea to serialize immutable data from an association?
Is it a good idea to serialize immutable data from an association?

Time:12-11

Let's say we have a collection of products, each with their own specifics e.g. price.

We want to issue invoices that contain said products. Using a direct association from Invoice to Product via :has_many is a no-go, since products may change and invoices must be immutable, thus resulting in an alteration of the invoice price, concept, etc.

I first thought of having an intermediate model like InvoiceProduct that would be associated to the Invoice and created from a Product. Each InvoiceProduct would be unique to its parent invoice and immutable. This option would increase the db size significantly as more invoices get issued though, so I think it is not a good option.

I'm now considering adding a serialized field to the invoice model with all the products information that are associated to it, a hash of the collection of items the invoice contains. This way we can have them in an immutable manner even if the product gets modified in the future.

I'm not sure of possible mid or long term downsides to this approach, though. Would like to hear your thoughts about it.

Also, if there's some more obvious approach that I might have overlooked I'd love to hear about it too.

Cheers

CodePudding user response:

In my experience, the main downside of a serialized field approach vs the InvoiceProducts approach described above is decreased flexibility in terms of how you can use your invoice data going forward.

In our case, we have Orders and OrderItems tables in our database and use this data to generate sales analytics reports as well as customer Invoices.

Querying the OrderItem data to generate the sales reports we need is much faster and easier with this approach than it would be if the same data was stored as serialized data in the db.

CodePudding user response:

No.

Serialized columns have no place in a modern application. They are a overused dirty hack from the days before native JSON/JSONB columns were widespread and have only downsides. The only exception to this rule is when you're using application side encryption.

JSON/JSONB columns can be used for a limited number of tasks where the data defies being defined by a fixed schema or if you're just storing raw json responses - but it should not be how you're defining your schema out of convenience because you're just shooting yourself in the foot. Its a special tool for special jobs.

The better alternative is to actually use good relational database design and store the price at the time of sale and everything else in a separate table:

class Order < ApplicationRecord
  has_many :line_items
end
# rails g model line_item order:belongs_to product:belongs_to units:decimal unit_price:decimal subtotal:decimal
# The line item model is responsible for each item of an order 
# and records the price at the time of order and any discounts applied to that line
class LineItem < ApplicationRecord
  belongs_to :order
  belongs_to :product
end
class Product < ApplicationRecord
  has_many :line_items
end 

A serialized column is not immutable in any way - its actually more prone to denormalization and corruption as there are no database side constraints to ensure its correctness.

Tables can actually be made immutable in many databases by using triggers.

Advantages:

  • No violation of 1NF.
  • A normalized fixed data schema to work with - constraints ensure the validity of the data on the database level.
  • Joins are an extremely powerful tool and not as expensive as you might think.
  • You can actually access and make sense of the data outside of the application if needed.
  • DECIMAL data types. JSON/JSONB only has a single number type that uses IEEE 754 floating point.
  • You have an actual model and assocations instead of having to deal with raw hashes.
  • You can query the data in sane queries.
  • You can generate aggregates on the database level and use tools like materialized views.
  • Related