2009-05-13 4 views
16

Perché è considerato OK avere un campo Id nelle entità dominio? Ho visto diverse soluzioni che forniscono una classe base con Id e GetHashCode/Equals basati su ID.DDD: chiavi primarie (Id) e ORM (ad esempio, NHibernate)

La mia comprensione del modello di dominio è che dovrebbe contenere solo le cose relative al dominio. Mentre in rari casi (ordini tracciabili) gli ID sono significativi, il più delle volte non forniscono nulla se non un modo semplice per fare riferimento agli oggetti in DB/sull'interfaccia utente.

Non vedo A è uguale a/benefici GetHashCode sia, dal momento che l'attuazione di identità mappa dovrebbe garantire che l'uguaglianza di riferimento è l'uguaglianza id comunque.

Stranamente, non riesco a trovare facilmente quello che pensano gli altri su questo argomento, quindi lo chiedo qui. Qual è l'opinione generale sull'uso di ID non relativi al dominio nelle entità di dominio? E ci sono problemi con NHibernate se non aggiungo Id alle mie entità di dominio?

UPDATE:

Grazie per le risposte.

Molti di loro suggeriscono che avere Id è l'unico modo per l'ORM di fare un aggiornamento del DB. Non penso che sia così. ORM tiene già traccia di tutte le entità caricate dal DB, quindi dovrebbe essere facilmente in grado di ottenere un ID internamente quando ne ha bisogno.

UPDATE 2:

risposta alla giustizia e simili punti: Che cosa succede se abbiamo un'applicazione web e necessità un modo per fare riferimento al soggetto tra le sessioni? Come modificare/risorsa/id?

Bene, vedo questo come una necessità specifica dell'interfaccia utente/ambiente vincolata, non di un modello di dominio necessario. Avere un servizio applicativo o un repository con il metodo GetIdentitity (coerente con il metodo Load (identità)) sembra essere sufficiente per questo scenario.

+1

Come implementare GetIdentity se non si dispone di un identificativo? Otterrai l'oggetto dal client e dovrai cercare l'identità. Come lo troveresti? I contenuti dell'oggetto potrebbero essere stati modificati sul client. Non lo troveresti più. Ho anche risposto ai tuoi commenti alla mia risposta. –

+0

Non mi riferisco al fatto quando ottengo un oggetto dal client. In questo caso, probabilmente ho un DTO con ID (e questo è rilevante anche se non ho un DB e memorizzo tutto in memoria, in questo caso l'id in DTO può essere una chiave in qualche Hashtable interno). Ma prima di inviare un oggetto al client, posso ottenere un ID e aggiungerlo al DTO che sto inviando. O semplicemente invia un ID in alcuni casi. –

+0

Ho appena trovato nella documentazione NH che NH non ha bisogno di una proprietà id! Vedi la mia risposta, ho aggiunto una sezione. –

risposta

4

riesco proprio a parlare di NHibernate. C'è bisogno di un campo per la chiave primaria, spetta a te se si prendono dati aziendali (non consigliato) o una chiave surrogata senza alcun significato commerciale.

scenari tipici sono:

  • incremento automatico valore generato dal database
  • GUID generato da NHibernate
  • GUID generato dalla logica di business

v'è un grande vantaggio avere un ID unico Quando si passa l'oggetto in giro, ad esempio sul client e di nuovo sul server, non è possibile fare affidamento sull'identità della memoria. Potresti persino avere diverse istanze in memoria della stessa istanza di business. L'istanza di business è identificata dall'ID.

Il confronto basato su ID è una questione di gusti. Personalmente mi piace il codice semplice e affidabile, e il confronto basato su ID è semplice e affidabile, mentre il confronto diretto è sempre un po 'rischioso, soggetto a errori, non mantenibile. Quindi si finisce con operatore == confrontare l'identità della memoria e Equals confrontando l'identità del business (e del database).

NHibernate è il modo meno intrusivo di mappare un modello di classe in un database relazionale che conosco. Nel nostro grande progetto abbiamo le chiavi primarie e le proprietà della versione (sono utilizzate per il blocco ottimistico). Si potrebbe sostenere che questo è invadente, perché non viene utilizzato per la logica di business.

NH non richiede di avere queste proprietà. (tuttavia ha bisogno di una delle proprietà come chiave primaria). Ma considera:

  • Funziona meglio, ad es.blocco pessimistico è possibile solo con una proprietà del caso,
  • più veloce: int ID di prestazioni migliori su molti database poi altri tipi di dati
  • e più facile: prendere le proprietà con un significato per l'azienda sono scoraggiati per diversi motivi.

Allora perché rendere la vita più difficile del necessario?


Edit: appena letto the documentation e ha scoperto che NHibernate fa non bisogno di una proprietà id nella classe persistente! Se non si dispone di un identificatore, you can't use some features. Si consiglia di averlo, ti semplifica la vita.

+1

Il passaggio client-server è un caso d'uso specifico - è risolvibile avendo un provider di identità o metodi di deposito che vengono utilizzati per questo caso specifico (GetId (oggetto), GetById (id)). Inoltre, non vedo differenze tra l'identità della memoria e l'identità aziendale se usiamo un ORM. Per quanto ho capito, all'interno di una sessione ci sarà sempre un singolo oggetto con un dato Id (eccetto le proiezioni, ma queste non sono comunque interessanti da confrontare). –

+2

Vedo il motivo per cui la chiave dati aziendale non è consigliata, ma la mia domanda iniziale riguarda l'utilizzo di una chiave surrogata, ma solo nel DB, a cui appartiene. Quindi gli svantaggi non dovrebbero applicarsi se NHibernate conosce la chiave DB surrogata - Io non voglio definirlo nelle mie entità di dominio. –

+0

Vuoi dire: SE non hai un'applicazione client-server, E non devi mai passare oggetti da una sessione all'altra (ad esempio, trasferire nel tempo, rete, file) E non hai bisogno di un'identificazione aziendale surrogata, POI potrebbe NHibernate gestisce internamente la chiave primaria del database. Questo è probabilmente vero, ma questo sarebbe un caso molto raro con limitazioni naturalmente forti. Potresti proporlo come miglioramento delle funzionalità in Jira di NHibernate. O implementalo come patch. –

0

È necessario averlo in un modo o nell'altro in modo che l'ORM possa tornare al database per eseguire gli aggiornamenti; Immagino che potrebbe essere privato e nascosto in una classe base, ma questo violare il concetto POCO.

+0

Vedere l'aggiornamento del post, penso che l'ORM conosca Id comunque, può semplicemente utilizzare la Mappa di identità al contrario. –

+0

Stai dicendo che l'ORM tiene traccia di tutti gli oggetti attualmente presenti nel sistema? Non posso dire per certo, ma sembra improbabile. –

+0

All'interno di una sessione, sì, dovrebbe. A seconda della configurazione, la sessione può essere una richiesta Web o addirittura un'intera durata del thread o dell'applicazione. Il motivo è che quando chiami SubmitChanges deve sapere quali sono le modifiche. E la maggior parte degli ORM AFAIK implementano anche http://martinfowler.com/eaaCatalog/identityMap.html che significa anche che devono sapere cosa hanno già. –

0

presupponendo che l'ID sia la chiave primaria, non sarà possibile salvare alcun dato nel DB senza di esso.
Per quanto riguarda gli uguali e GetHashCode, questi sono per l'ordine negli elenchi in cui si crea un ordine personalizzato.

Grazie per le risposte.

Molti di loro suggeriscono che avere Id è l'unico modo per l'ORM di fare un aggiornamento del DB. Non penso che sia così. ORM tiene già traccia di tutte le entità caricate dal DB, quindi dovrebbe essere facilmente in grado di ottenere un ID internamente quando ne ha bisogno.

Sarei molto sorpreso se fosse il caso. Di solito crea un'istruzione di inserimento solo dalle proprietà che hai definito.

+0

Vedere l'aggiornamento del post, penso che l'ORM conosca l'ID internamente. –

+0

Sarei molto sorpreso se fosse il caso. Di solito crea un'istruzione di inserimento solo dalle proprietà che hai definito. Sì, perché nella maggior parte dei casi ha senso. Tuttavia, un buon ORM ha anche una versione precedente del tuo oggetto e, in generale, può memorizzare tutte le informazioni sul tuo oggetto che desidera. Ho semplicemente cercato su Google un esempio su come aggiungere dati aggiuntivi a un inserto: http://www.dav-evans.com/?p=75. –

0

Non ci sono altre opzioni per ottenere lo stesso oggetto senza identità.Ad esempio, le persone hanno un codice di sicurezza sociale o un codice personale o qualcosa che è unico e possiamo identificarli con esso.

È possibile utilizzare l'identità naturale ma che è soggetta a errori.

Basta rinominare Id to Identity. Sembra più bello nel modello di dominio.

Le entità sono denominate entità perché hanno identità.

+0

Per situazioni Web e altri casi simili, sarà sufficiente una sorta di IIdentityService che potrebbe effettivamente essere NHibernateIdentityService (ma è un caso specifico quando si desidera fare riferimento a un determinato oggetto per il recupero futuro, non abbastanza generico per il modello di dominio). –

0

In genere includo l'ID nel dominio come classe Entity di base. Non conosco altri modi per usare un ORM.

Un oggetto nel dominio è già univoco dal suo riferimento, utilizzando un ID per determinare l'unicità/l'uguaglianza non è poi così diverso nella pratica. Finora non ho riscontrato un serio effetto collaterale su questo approccio.

-1

È inoltre possibile utilizzare più campi per stabilire l'identità, denominata tasti compositi. Ciò richiederà più lavoro da parte tua, comunque.

venirne a conoscenza in here

+0

Significa che dovrò avere la stessa chiave primaria nella tabella? –

+0

Beh, sì, l'identità in nhib deve essere l'identità nel db .. è una specie del punto .. –

1

In Nh, non è possibile utilizzare l'uguaglianza di riferimento per le istanze distaccate. Questo ti fa usare l'NH nei clienti che vorrebbero usare questo comportamento (secondo me questo è il comportamento corretto, NH non dipende dalla magia!).

Nelle app Web o negli usi basati su sessioni in cui è possibile accedere al db nell'ambito di un'ISession, penso di avere ragione nel dire che si può fare affidamento sull'uguaglianza di riferimento. Ma in uno scenario smart client o, più specificamente, in uno scenario in cui due ISessioni condividono un'istanza (una caricata da o inserita nel db, quindi passata alla seconda), è necessario che i campi id db siano archiviati insieme a l'istanza.

la seconda sessione di seguito non avrebbe idea che l'istanza che è stata passata è già stata inserita e richiede un aggiornamento, e anche se è stata modificata in un aggiornamento, presumo che abbia ragione nel pensare che non stia andando per conoscere l'ID DB della classe.

class SomeEntityWithNoId 
{ 
public blah etc {} 
} 

class dao 
{ 

void DateMethod() 
{ 
var s1 = sessionFactory.OpenSession(); 
var instance = new SomeEntityWithNoId(); 
instance.Blah = "First time, you need to insert"; 
s1.Save(s1); //now instance is persisted, has a DB ID such as identity or Hilo or whatever 
s1.close(); 
var s2 = sessionFactory.OpenSession(); 
s2.Blah = "Now update, going to find that pretty hard as the 2nd session won't know what ID to use for the UPDATE statement"; 

s2.Update(instance); //results in boom! exception, the second session has no idea *how* to update this instance. 




} 
} 

Se siete preoccupati per il campo ID (s), che lei ha ragione nel pensare è in gran parte inutile per qualcosa di diverso da preoccupazioni di persistenza, è possibile renderli privati, così almeno questo comportamento e la semantica sono incapsulati . Potresti scoprire che questo approccio crea qualche attrito nel TDD.

Penso che tu abbia ragione sulle mappe ID per quanto riguarda NH almeno. Se l'istanza è transitoria quando viene collegata per la prima volta alla sessione, il tipo non ha bisogno di memorizzare il proprio ID db in un campo. Penso che la sessione saprà come gestire la relazione con il db. Sono sicuro che è possibile interrompere un test per dimostrare questo comportamento; p

+0

Sono d'accordo con il tuo post, ma non credo che l'esempio fornito (2 sessioni successive con un oggetto) sia un caso d'uso comune per l'NHibernate. L'invio di oggetti dal server al client è un'altra storia, ma in questo caso potrebbero essere DTO o disporre di un serializzatore personalizzato che consente di inviare/ricevere Id. –

3

In genere, non si disporrà di un modello di dominio vero. Avrai innumerevoli sessioni concomitanti e sequenziali, che devono essere coordinate, e ognuna delle quali contiene al suo interno un modello di dominio transazionale in miniatura. Non avrai le stesse istanze dell'oggetto tra due sessioni simultanee o tra due sequenziali. Ma avrai bisogno di un modo per assicurarti di poter spostare le informazioni da una sessione all'altra.

Un esempio, naturalmente, è una coppia di/resource/list e/resource/show/id di URL (corrispondente ad una coppia appropriata di azioni del controller in asp.net mvc). Passando dall'uno all'altro, ci sono due sessioni completamente indipendenti, ma devono comunicare tra loro (tramite HTTP e browser).

Anche senza l'utilizzo di un database, il dominio oggetti del modello saranno ancora bisogno di qualche forma di identità, perché si avrà ancora numerosi in miniatura, modelli di dominio isolati, non il modello unico vero dominio; e avrai tutti questi modelli di dominio in sessioni indipendenti contemporaneamente e una dopo l'altra.

L'uguaglianza dell'oggetto non è sufficiente, poiché gli oggetti non sono uguali tra le sessioni anche se le entità concettuali sottostanti che rappresentano rappresentano la stessa entità.

+2

Grazie per il punto ben descritto. Vedi l'aggiornamento post 2. Accetto che sia necessario un sistema di riferimento/identità serializzabile se si desidera fare/resource/show/id, ma sembra un vincolo specifico del Web, non un requisito di dominio. Ma per quanto riguarda l'uguaglianza, non mi sembra che ci sia un motivo per confrontare gli oggetti di diverse sessioni. –

+0

Lo schema dell'unità di lavoro o di sessione richiederebbe che, anche in un'app desktop senza un database, gli oggetti del modello di dominio dispongano di identificatori permanenti univoci che sono uguali per tutte le sessioni, anche se gli oggetti stessi non sono gli stessi tra le sessioni. – yfeldblum