Sérialisation au niveau de la base de données

Bonjour, Habr!


Je me suis assis une fois et j'ai essayé de donner au JSON avant des biens immobiliers, qui avaient beaucoup de dépendances. Symfony 4, knp pagination et JMSSerializer se tenaient à l'arrière, enfin, en principe, des choses standard, mais le problème est que lorsque vous essayez de donner un objet avec toutes les entités et collections imbriquées, tout commence à ralentir au niveau de la sérialisation de ces données.


Vous devez d'abord faire une demande à la base de données, puis le sérialiseur récupérera progressivement tout le reste, puis tout sera enveloppé dans JSON et seulement alors tout reviendra au premier plan.


Idée


J'ai eu une idée, pourquoi ne pas retourner JSON directement de la base de données directement à l'avant de l'arrière, oui, vous devez écrire du SQL génial, mais vous pouvez créer un outil qui le fait pour vous. J'ai commencé à écrire une idée, un référentiel sur un github , basé sur le modèle de données de la doctrine, les communications OneToOne, ManyToOne, OneToMany et ManyToMany. De plus, cet outil peut être facilement vissé sur Symfony 4 et il se configurera lui-même, en conséquence, vous n'avez qu'à injecter la fabrique QueryBuilderFactory et à partir de là QueryBuilder pour la table souhaitée par classe d'entité.


Mon sérialiseur utilise également des groupes de sérialisation que vous pouvez définir à l'aide de l'annotation d'exposer sur le champ d'entité, n'oubliez pas de joindre également l'annotation de table à l'entité et de spécifier l'alias de table, il est préférable d'utiliser ceux que vous spécifiez habituellement.


Exemple de génération SQL


<?php use \Mash\MysqlJsonSerializer\QueryBuilder\Table\JoinStrategy\FieldStrategy; use \Mash\MysqlJsonSerializer\Wrapper\FieldWrapper; use \Mash\MysqlJsonSerializer\QueryBuilder\Table\Table; use \Mash\MysqlJsonSerializer\Wrapper\Mapping; use \Mash\MysqlJsonSerializer\QueryBuilder\QueryBuilder; $oneToManyTable = (new Table('advert_group', 'adg', 'adg_id')) ->addSimpleField('adg_id') ->addSimpleField('adg_name') ; $table = (new Table('estate', 'est', 'est_id')) ->addSimpleField('est_id') ->addSimpleField('est_name') ->addOneToManyField($oneToManyTable, 'advert_groups', new FieldStrategy('adg_estate')); $mapping = new Mapping(); $mapping ->addMap($table, 'est_id', 'id') ->addMap($table, 'est_name', 'name') ->addMap($oneToManyTable, 'adg_id', 'id') ->addMap($oneToManyTable, 'adg_name', 'name'); $builder = new QueryBuilder($table, new FieldWrapper($mapping)); $builder ->setOffset(2) ->setLimit(1); $sql = $builder->jsonArray(); 

Par conséquent, le code SQL suivant sera généré:


 SELECT JSON_ARRAYAGG(JSON_OBJECT('id',est_res.est_id,'name',est_res.est_name,'advert_groups',(SELECT JSON_ARRAYAGG(JSON_OBJECT('id',adg.adg_id,'name',adg.adg_name)) FROM advert_group adg INNER JOIN estate est_2 ON est_2.est_id = adg.adg_estate WHERE est_2.est_id = est_res.est_id))) FROM (SELECT * FROM estate est LIMIT 1 OFFSET 2) est_res 

Résultat:


 [{"id": 3, "name": ",  , 31", "advert_groups": [{"id": 10, "name": "avito-1115362430"}]}] 

Résumé


Des instructions d'utilisation complètes seront bientôt ajoutées au référentiel github. En conséquence, quand je l'ai vissé dans mon projet, j'ai reçu des réponses très rapides de l'API REST et en même temps j'ai pu retourner beaucoup d'objets avec beaucoup de dépendances imbriquées, par exemple, ce que je voulais obtenir via JMSSerializer que j'ai obtenu pendant 40 secondes, maintenant pour 230 millisecondes, et cela à condition que l'abonné du noyau lise les annotations sur les champs d'entité par réflexion, je veux l'implémenter bientôt via le cache Symfony.


L'article sera complété ...


Deuxième partie

Source: https://habr.com/ru/post/fr438460/


All Articles