Domain-Driven Design, part 7 — Alternative Relational Database Mapping

Product Name Story

We worked on an e-shop and the product had exactly one name. One day we faced confronted with the reality — the e-shop has to be multilingual. I imagined a new database table for every language field immediately, and I was disgusted by all the tables that had to be created. But luckily I asked myself — What is the domain?

Use cases

The domain can be extracted from stories and use cases. We discussed this in our team and we extracted a couple of use cases:

  • Show the product name in the language
  • If the name in language is missing, show an empty string

LangValue Extraction

Use cases were the same for all names or descriptions in the system that had to be multilingual. So we decided to extract use cases and responsibility into a common LangValue.

Relational Database Storage

The LangValue works great in objects but how to save it into a relational database? Well, we could think that text in language must be in a separate table. That would be difficult to map, even impossible without changing the domain model.

Serialization

We decided to use LangValue serialization.

Example of serialized object

{
"cs-CZ": "Televize",
"en-GB": "Television",
"es-ES": "televisión",
"ru-RU": "телевидение"
}

LangValue Doctrine Mapping

We need to convert the LangValue to the JSON and vice versa.

Registration

We have to add code to the Doctrine integration.

\Doctrine\DBAL\Types\Type::addType(LangValueType::LANG_VALUE, LangValueType::class);/** @var Doctrine\DBAL\Connection */
$connection = ...;
$platform = $connection->getDatabasePlatform();
$platform->registerDoctrineTypeMapping(LangValueType::LANG_VALUE, LangValueType::LANG_VALUE);

Mapping

Database Search in JSON

A relational database isn’t usually a good choice for a full-text search. But some databases allow us to query the JSON data type anyway.

PostgreSQL

SELECT * FROM Product where name->>'cs-CZ' LIKE '%query%';

MySQL

SELECT * FROM Product where name->'$.cs-CZ' LIKE '%query%';

TL;DR

Think before mapping. Even if you are experienced, you can find some new and creative mapping styles. Focus on use cases, do the object model first and think about relations and mapping later. JSON object serialization is useful.

References

DOCTRINE TEAM. Custom Mapping Types — Doctrine 2 ORM 2 documentation [online]. 2018 [2018–03–14]. Available: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/cookbook/custom-mapping-types.html

Contact

Are you designing architecture and like DDD approach? Hire me, I can help you — svatasimara.cz

Developer interested in Domain-Driven Design & Modeling