Serialização no nível de banco de dados

Olá Habr!


Sentei-me uma vez e tentei dar JSON à frente com imóveis, que tinham muitas dependências. Symfony 4, paginação knp e JMSSerializer estavam na parte de trás, bem, em princípio, coisas padrão, mas o problema é que, quando você tenta fornecer um objeto com todas as entidades e coleções aninhadas, tudo começa a ficar mais lento no nível de serialização desses dados.


Primeiro, você precisa fazer uma solicitação ao banco de dados, o serializador puxará gradualmente todo o resto, depois tudo será envolto em JSON e só então tudo voltará à frente.


Idéia


Tive uma ideia: por que não retornar JSON diretamente do banco de dados diretamente para a frente, por trás? Sim, você precisa escrever um SQL incrível, mas pode criar uma ferramenta que faça isso por você. Comecei a escrever uma ideia, um repositório em um github , com base em um modelo de dados da doutrina, nas comunicações de OneToOne, ManyToOne, OneToMany e ManyToMany. Além disso, essa ferramenta pode ser facilmente parafusada no Symfony 4 e, como resultado, você se configurará; portanto, você só precisará injetar a fábrica QueryBuilderFactory e, a partir daí, QueryBuilder para a tabela desejada por classe de entidade.


Meu serializador também usa grupos de serialização que você pode definir usando a anotação Expor no campo entidade, não se esqueça de anexar a anotação Tabela à entidade e especificar o alias da tabela; é melhor usar os que você costuma especificar.


Exemplo de Geração 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(); 

Como resultado, o seguinte SQL será gerado:


 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 

Resultado:


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

Sumário


Em breve, instruções completas de uso serão adicionadas ao repositório do github. Como resultado, quando estraguei tudo isso no meu projeto, recebi respostas muito rápidas da API REST e, ao mesmo tempo, consegui retornar muitos objetos com muitas dependências aninhadas, por exemplo, o que queria obter através do JMSSerializer por 40 segundos, agora por 230 milissegundos, e isso desde que o Kernel Subscriber leia anotações nos campos da entidade por meio de reflexão, eu quero implementar isso em breve através do cache Symfony.


O artigo será complementado ...


Segunda parte

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


All Articles