2014-05-02 12 views
7

Ero curioso di sapere quali sono le opinioni della gente su come mantenere l'ID di un'entità DAL come una proprietà dell'entità di dominio, al massimo una proprietà di sola lettura.Identità di persistenza e entità modello di dominio

Il mio primo pensiero è che va bene, ma più ci penso e più non mi piace l'idea. Dopotutto, il modello di dominio dovrebbe essere completamente inconsapevole del modo in cui i dati vengono mantenuti, e la conservazione e la proprietà Id su ciascun modello di dominio è un'indicazione meno che sottile. Il livello di persistenza può essere qualcosa che non richiede chiavi primarie, o un'altra proprietà esposta nel modello di dominio può essere un candidato adatto per l'identificazione, un modello no. Forse.

Ma poi questo mi ha fatto pensare, per i modelli di dominio che non dispongono di un mezzo affidabile per identificare in modo univoco una voce in un livello di persistenza del database, come devono identificare le voci quando si tratta di aggiornamento o eliminazione?

Un dizionario basato su chiavi di riferimento deboli potrebbe fare il trucco; WeakDictionary<DomainEntity, PrimaryKeyType>. Questo dizionario sarebbe una parte dell'implementazione del repository, ogni volta che il client del repository Fetch's una raccolta di DomainEntity un riferimento debole all'entità e il relativo ID del livello di persistenza viene memorizzato in questo dizionario interno tale che quando arriva il momento di restituire la modifica entità al repository per l'aggiornamento del livello di persistenza, il seguente potrebbe essere fatto per recuperare l'Id

PrimaryKeyType id = default(PrimaryKeyType); 
if (!weakDictionary.TryGetValue(someDomainEntity, out id)) 
    // id not found, throw exception? custom or otherwise.. 

// id found, continue happily mapping domain model back to data model. 

I vantaggi di questo approccio come la vedo io, è l'entità del dominio non deve mantenere la sua specifica id strato di persistenza e il repository ti obbliga ad avere un'entità di dominio legittima ottenuta tramite alcune chiamate a un metodo Fetch... o al metodo Add/CreateNew, e Se dovessi provare ad aggiornare/eliminare l'entità, genererebbe un'eccezione.

Sono consapevole del fatto che probabilmente si tratta di un eccesso di ingegnerizzazione e dovrei limitarmi a diventare pragmatico, ero solo curioso di sapere cosa ne pensavano gli altri.


Non voglio iniziare un'altra discussione solo per questa domanda secondaria in quanto è in qualche modo correlata. Ma dal momento che è relativamente recente ho iniziato a cercare in DDD (anche se in questo caso il mio database è venuto prima) Mi chiedevo se potessi confermare di avere la mentalità giusta per le entità di dominio, ecco un esempio ridotto della mia entità di dominio Employee.

public class Employee : DomainEntity 
{ 
    public string FirstName { get; } 
    public string LastName { get; } 
    public UserGroup Group { get; } 
    // etc.. 


    // only construct valid employees 
    public Employee(string firstName, string lastName, SecureString password, UserGroup group); 

    // validate, update. (not sure about this one.. pulled it 
    // from an open source project, I think that names should be able to be set individually). 
    AssignName(string firstName, string lastName); 

    // validate, update. 
    ResetPassword(SecureString oldPassword, SecureString newPassword); 

    // etc.. 
} 

Grazie!

+0

Si dovrebbe ridurre un po 'il verbage e porre una domanda _real_ (non una discussione) se si desidera rispondere a questa domanda (e rimanere aperta) – Shoe

+4

@ShoeMay: Non sono d'accordo. Questa è una domanda pertinente e ben strutturata. I concetti di implementazione del DDD sono spesso pesantemente appesantiti da domande di progettazione come questa. – davenewza

risposta

4

La tua proposta di utilizzare riferimenti deboli ha un difetto principale.

Come forse sapete, le entità di dominio hanno la caratteristica importante in quanto devono avere identità. Questo è importante per ragioni di confronto. Se due entità hanno la stessa identità, indipendentemente dai valori delle loro proprietà, allora sono considerati uguali:

Entity1 == Entity2 ⇔ Entity1.Identity == Entity2.Identity 

Un tipico "design pattern" sarebbe ereditare tutte le entità da una classe astratta DomainEntity<T>, che sostituisce il confronto di questi oggetti e confronto per identità.

Ora, considera il tuo approccio di utilizzare una ricerca di riferimento debole. Facciamo un esempio:

Si preleva un Entity1, ad esempio l'utente "Reegan Layzell", da un repository.Quindi si recupera nuovamente la stessa entità "Reegan Layzell" dal repository come Entity2. Ora hai la stessa entità nel tuo dominio in due oggetti. Ma hanno riferimenti differenti (ovviamente).

Quando si confrontano, queste entità non saranno considerati uguali nel dominio.

Ammiro il vostro paura di introdurre le preoccupazioni di database nel modello di dominio, ma propagare l'ID del database nelle vostre entità è difficilmente andando ad incidere sulla qualità dei modelli e ti farà risparmiare un sacco di guai. Come hai detto tu, dobbiamo essere pragmatici.

Per quanto riguarda la tua Employee esempio: Vuol AssignName davvero senso? In realtà, il nome di un dipendente può davvero cambiare dopo la creazione? Oltre a questo, sembra che tu abbia l'idea giusta. Consiglio vivamente di guardare questo: Crafting Wicked Domain Models di Jimmy Bogard.

+0

In realtà ero a conoscenza di questo problema e l'ho risolto implementando una serie di classi private nella mia implementazione 'WeakDictionary'. Uno dei quali fa il confronto tra i riferimenti deboli sovrascrivendo i metodi Equals/GetHashCode tramite l'Identità dell'entità debolmente referenziata. Il problema che ho ora è rimuovere automaticamente l'entità dal dizionario quando il riferimento è perso. Non c'è un gancio per me fare qualcosa del genere .. almeno facilmente. È ancora un work in progress ma qui, dai uno sguardo http://pastebin.com/Vt73HJzk – rtlayzell

+0

Ho testato lo scenario che hai menzionato e tutto funzionava bene, la classe stessa è un WIP e io uso un timer per fare il pulizia automatica (soluzione ad hoc), ottimo collegamento tra l'altro, l'ho già visto ma ci dovrebbero essere altri video come questo, che riguardano DDD – rtlayzell

+0

Inoltre, sono giunto alla conclusione che questi ID tecnici sono necessari per suddividere i grandi aggregati basta che faccia riferimento a una particolare entità piuttosto che esserne responsabile. Per esempio in uno dei miei progetti ho una radice aggregata 'Appointment' che richiede un riferimento a un' Client', 'Employee', e un' Service' che sono i propri Aggregati, invece di caricarli e persisterli tramite Appuntamento ha senso memorizzare semplicemente un riferimento a loro tramite il loro ID poiché questa è l'unica cosa richiesta dal dominio – rtlayzell

Problemi correlati