Repository pattern met custom SQL en niet-entity classes

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • gnoe93
  • Registratie: September 2016
  • Laatst online: 08-04 13:00
Binnen een Symfony 3 en Doctrine project gebruik ik repositories die per entity gemapt zijn. In de meeste gevallen werk ik rechtstreeks met de entities die ik terugkrijg uit de repositories, maar in sommige gevallen is het nodig om complexe SQL/DQL queries te schrijven die niet direct naar mijn bestaande entities gemapt kunnen worden.

Een voorbeeld van zo een query is uit mijn database van "kaarten" een overzicht halen hoeveel van een specifieke kaart de gebruiker in zijn verzameling heeft per kaartconditie.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
SELECT
    cardCondition.id,
    cardCondition.name,
    COALESCE(cardVariantInCollection.amount, 0) AS amountHave
FROM
    AppBundle:CardCondition cardCondition INDEX BY cardCondition.id
    LEFT JOIN AppBundle:CardVariantInCollection cardVariantInCollection
        WITH cardVariantInCollection.cardCondition = cardCondition.id
        AND cardVariantInCollection.user = :userId
        AND cardVariantInCollection.cardVariant = (
            SELECT
                cardVariant.id
            FROM
                AppBundle:CardVariant cardVariant
            WHERE
                cardVariant.card = :cardId
                AND cardVariant.cardVariantType = :cardVariantTypeId
        )
ORDER BY
    cardCondition.id ASC


Het resultaat past dus niet binnen mijn entities en wordt standaard als assoc array teruggegeven. Omdat het resultaat op meerdere plaatsen gebruikt wordt, lijkt het me verstandig het resultaat naar een klasse te mappen ipv een assoc array te gebruiken.

Hierbij heb ik 2 vragen:

1. Is het mogelijk doctrine custom hydration te laten doen naar een niet-entity klasse?

2. Indien ja, waar breng ik deze classes best onder binnen mijn applicatiearchitectuur? Momenteel zitten mijn entities in een AppBundle\Entity namespace en mijn repositories in een AppBundle\Repository namespace. Deze classes zijn eigenlijk voornamelijk containers voor de teruggekregen data, dus ik weet niet zeker of dit wel binnen mijn domain laag past. Aangezien ze sterk gekoppeld zijn met de repository zelf, misschien AppBundle\Repository\Model?

Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Wat ik meestal doe in grotere projecten is het optuigen van managers voor de grote entiteiten. Ik heb recent bijvoorbeeld een groot matchmaking project afgerond en daar zitten drie managers in: een UserManager, een TournamentManager en een MatchManager. Die drie spelen (onder andere) voor proxy tussen mijn controllers en mijn repositories. De repository kan daarmee gewoon hetzelfde blijven doen dat je nu hebt en de manager maakt er beter bruikbare code van.

Om daarmee terug te komen op je vraag: Doctrine kan geen objecten hydraten die hij niet managet, dus dat gaat niet zomaar. Je kan dat dus zelf in je manager doen, naar of dat handig is, is een tweede. Als je dat doet maakt de namespace niet heel veel uit, maar dan zou ik eerder denken aan AppBundle\Entity\Unmanaged.

[ Voor 25% gewijzigd door NMe op 16-07-2017 12:13 ]

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • gnoe93
  • Registratie: September 2016
  • Laatst online: 08-04 13:00
NMe schreef op zondag 16 juli 2017 @ 12:10:
Wat ik meestal doe in grotere projecten is het optuigen van managers voor de grote entiteiten. Ik heb recent bijvoorbeeld een groot matchmaking project afgerond en daar zitten drie managers in: een UserManager, een TournamentManager en een MatchManager. Die drie spelen (onder andere) voor proxy tussen mijn controllers en mijn repositories. De repository kan daarmee gewoon hetzelfde blijven doen dat je nu hebt en de manager maakt er beter bruikbare code van.

Om daarmee terug te komen op je vraag: Doctrine kan geen objecten hydraten die hij niet managet, dus dat gaat niet zomaar. Je kan dat dus zelf in je manager doen, naar of dat handig is, is een tweede. Als je dat doet maakt de namespace niet heel veel uit, maar dan zou ik eerder denken aan AppBundle\Entity\Unmanaged.
Bedoel je dan de niet entity-gebonden SQL verhuizen naar een dergelijke manager? Zou je dat niet beter binnen de repository/persistencelaag houden?

Wat doctrine en het hydraten betreft, heb ik inderdaad ook net gelezen dat dit niet mogelijk is. De beste optie lijkt me om over de result rows te loopen, en ze via een statische initializeFromArray() methode in een object steken.

Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

gnoe93 schreef op zondag 16 juli 2017 @ 12:25:
[...]


Bedoel je dan de niet entity-gebonden SQL verhuizen naar een dergelijke manager? Zou je dat niet beter binnen de repository/persistencelaag houden?
Nee, de SQL hoort uiteraard in je repositories thuis. De manager haalt die data op uit je repository en kan eventuele datatransformaties doen.

Ik wil mijn repositories altijd zo dom mogelijk hebben. Query doen, result returnen, niks meer.

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • gnoe93
  • Registratie: September 2016
  • Laatst online: 08-04 13:00
NMe schreef op zondag 16 juli 2017 @ 12:30:
[...]

Nee, de SQL hoort uiteraard in je repositories thuis. De manager haalt die data op uit je repository en kan eventuele datatransformaties doen.

Ik wil mijn repositories altijd zo dom mogelijk hebben. Query doen, resoluut return, niks meer.
In de meeste gevallen is het waarschijnlijk mogelijk om de bestaande entities te transformeren, maar dit kan veel performanter (en minder) omslachtig met native SQL. Een ORM zal immers nooit perfect alle gegevens kunnen mappen ;).