Realizziamo il 100% di Persistenza Ignorance se non stiamo usando gli oggetti POCO di ORM per modellare il Dominio?

5

L'ignoranza della persistenza è la capacità di recuperare / persistere oggetti standard, in cui gli oggetti standard sono considerati classi focalizzate su particolari problemi aziendali e quindi non contengono infrastructure-related logic . In DDD viene utilizzato un modello di repository per ottenere PI.

Supponendo che non usiamo gli oggetti POCO di ORM per modellare il Dominio , allora i nostri oggetti Dominio non devono rispettare i requisiti di progettazione di un particolare O / RM (come usare costruttore predefinito o contrassegnare le proprietà come virtual ). Tali oggetti Dominio saranno considerati Persistenza Ignorante .

Ma se vogliamo che questi Oggetti Dominio supportino anche funzionalità come lazy loading , allora le loro proprietà devono contenere una logica che a un certo punto dovrebbe controllare se sono correlate i dati erano già stati caricati e, in caso contrario, avrebbe contattato il Repository appropriato e richiesto i relativi dati.

Ora anche se questi Oggetto Dominio sono completamente inconsapevoli di come vengono mantenuti e il loro Dominio è completamente disaccoppiato dal provider DAL sottostante , non potremmo ancora sostenere che tali Domain Ojects contengono Infrastructure-related logic e quindi violano ancora PI ?

    
posta user437291 08.01.2013 - 20:12
fonte

3 risposte

4

Dopo aver incontrato lo stesso problema, ecco la soluzione che ho implementato per questo.

Dominio

public class DomainObject : AggregateRootBase //implements IAggregateRoot
{
    private ChildEntity _ChildEntity = null;
    public ChildEntity ChildEntity
    {
        get
        {
            OnChildEntityRequested();
            return _ChildEntity;
        }
    }

    public event EventHandler ChildEntityRequested;
    protected void OnChildEntityRequested()
    {
        if (ChildEntityRequested != null) { ChildEntityRequested(this, new EventArgs()); }
    }

    public static void SetChildEntity(DomainObject destination, ChildEntity child)
    {
        //To set or not to set, that is the question.
        destination._ChildEntity = child;
    }
}

Implementazione del repository

public class DomainObjectRepository : List<DomainObjectTracker>, IDomainObjectRepository
{
    private void Load() //Method called by constructor or other loading mechanism.
    {
        foreach (DomainObjectDataModel dodm in ORMSystem) //Iterating through each object returned from ORM.
        {
             DomainObject do = Translate(dodm); //Translate into domain object.
             do.ChildEntityRequested += new EventHandler(DomainObject_ChildEntityRequested);
             DomainObjectTracker tracker = new DomainObjectTracker(do, dodm.Key);
             base.Add(tracker);
        }
    }

    protected void DomainObject_ChildEntityRequested(object sender, EventArgs e)
    {
        DomainObject source = sender as DomainObject;
        //Here, you could check to see if it is null or stale before loading it.
        //if (source.ChildEntity == null || IsStale(source.ChildEntity))

        DomainObjectTracker tracker = base[IndexOf(source)];
        ChildEntity entity = LoadChildEntity(tracker.Key); //Load the child entity from ORM.
        DomainObject.SetChildEntity(source, entity);
    }
}

Dopo aver esaminato la mia soluzione, potresti pensare: "Non sta chiamando un codice relativo all'infrastruttura degli eventi, ma sicuramente non si riferisce al mio dominio?". Anche se questo può essere vero, se ci pensi solo in termini di PI, allora ti rendi conto che stai solo offrendo un messaggio dal tuo dominio dicendo: "Ehi, sto per accedere a questa entità bambino". che consente al repository di rispondere con, "Aspetta, se ne hai bisogno uno (o uno nuovo), l'ho capito proprio qui nel mio db, quindi lascia che ti dica questo prima di continuare!".

Ci sono alcuni avvertimenti qui. Uno, significa che è necessario un evento per ogni entità figlio all'interno di un aggregato. Due, interrompe l'incapsulamento perché stai permettendo un modo pubblico di impostare l'entità figlio. Il rovescio della medaglia, i vantaggi sono il codice espressivo, le implementazioni dell'infrastruttura sono facilmente separate dal dominio, gli oggetti del dominio sono PI e l'ORM rimane incapsulato dietro l'implementazione del repository.

Se qualcuno ha un modo migliore di risolvere questo problema, sono tutto occhi!

Modifica Inoltre, anche se la mia risposta fornisce una soluzione per PI, sono d'accordo con i commentatori di cui sopra. Hai bisogno di valutare se DDD è la risposta giusta per te perché, mentre rende un progetto più facile da mantenere e semplifica quello che altrimenti sarebbe un progetto molto complesso, ha un costo (solitamente tempo di sviluppo in anticipo e formazione del tuo team per organizzare correttamente il codice e utilizzare i vari modelli).

    
risposta data 08.01.2013 - 21:34
fonte
2

Se si sceglie di non utilizzare ORM POCO per la logica del dominio, bene. Inoltre, rinunci a tutto ciò che viene fornito con essi, ad esempio il caricamento e il caching lazy, che diventano funzioni che devi rendere conto (se vuoi) come parte del tuo dominio o assumere che verranno fornite dall'ORM a un livello inferiore.

Un'altra sfida è il passaggio in più per spostare i dati avanti e indietro dai POCO di ORM ai POCO di dominio, cosa che può essere fatta con strumenti come Automapper ma causare problemi come l'aggiornamento di un oggetto che potrebbe essere necessario forzare l'ORM a recuperarlo in modo che possa essere aggiornato, a seconda di come è implementato l'ORM.

Quanto guadagni davvero richiedendo il 100% di purezza? La violazione del PI non è davvero così importante?

    
risposta data 08.01.2013 - 21:10
fonte
2

Qualsiasi ORM degno di questo nome non inquinerà il tuo modello con problemi di persistenza come il caricamento lento. Tipicamente questo sarà realizzato usando una tecnica come un proxy trasparente, che ha l'interfaccia dell'oggetto / collezione completamente caricato, ma ne rimanda il caricamento fino al suo accesso.

Se il tuo ORM non fa questo per te, vorrei suggerire umilmente di trovare un altro ORM.

Un ORM non dovrebbe forzare l'utente a disporre di una versione orientata alla persistenza del modello e di una versione orientata al dominio del modello e richiedere la mappatura tra i due modelli. Questo è ciò che fa un mappatore relazionale all'oggetto; questa è l'intera ragione per cui esiste.

    
risposta data 09.03.2016 - 16:55
fonte

Leggi altre domande sui tag