8

sto faticando un po 'con i repository. Sto usando C# e NHibernate. La domanda che ho è: quanto dovrebbe fare il mio repository prima di chiamare un salvataggio o un get?Quanta logica dovrei inserire i miei metodi di repository quando si utilizza il pattern del repository?

Ad esempio, ho una classe utente che è una radice aggregata. Voglio chiamare un metodo chiamato "register" che aggiungerà l'utente e imposterà alcuni valori predefiniti basati su regole aziendali e creerà alcune altre entità che sono anche parti secondarie della radice "utente" (es. Indirizzo, gruppi, ecc.). Devo chiamare

userRepo.Register(newUser); 

che sarebbe (ignorando i problemi evidenti):

Regsiter(User newUser){ 
newUser.SomeProp = "Default Data"; 
Group g= new Group; 
g.SomeProp2 = "Default Data"; 
newUser.Groups.Add(g); 
Session.Save(g); 
Session.Save(newUser); 
} 

o forse ho messo il registro in un livello di business e lo hanno fare:

Regsiter(User newUser){ 
newUser.SomeProp = "Default Data"; 
Group g= new Group; 
g.SomeProp2 = "Default Data"; 
newUser.Groups.Add(g); 
userRepo.Register(newUser, g);// this does session.save on both objects. 
} 

Entrambi sembra leggermente sbagliato.

Qual è l'approccio corretto?

modificare -------------------------------

grazie per tutte le risposte. Non riesco a decidere chi è il più giusto e quindi quale risposta accettare.

In generale, tutti dicono di mettere le regole aziendali in un altro livello. questo ha senso, ma non sono sicuro delle chiamate dati per i gruppi - poiché i gruppi non sono una radice aggregata non dovrebbero avere il loro repository, quindi come faccio ad aggiungerli e salvarli? Nel mio progetto l'aggiunta di un gruppo alla raccolta di gruppi dell'utente non crea automaticamente il gruppo nel db; Devo anche chiamare session.save sull'oggetto. così lo metto nel repository utente come userRepo.SaveGroup (g)?

Se si dispone di un createGroup() nell'altro layer, sarà necessario utilizzare il proprio repository o gli utenti. o sono di spessore?

risposta

3

Determinare dove si desidera che il metodo Register, forse in una classe UserServices. è possibile delegare la creazione di oggetti a un UserFactory. in un CreateNewUser (), impostare i valori predefiniti per l'utente e la raccolta Gruppi, quindi chiamare UserRepository.Save (newUser) per mantenere i dati.

// UserServices class 
public void Register(User newUser) 
{ 
    // add custom registration stuff. 
    _userRepository.Save(newUser); 
} 

// Application code 
User user = UserFactory.CreateNewUser(); 
_userServices.Register(user); 

// UserFactory 
public User CreateNewUser() 
{ 
    // all new user, group creation 
} 
+0

in questo esempio la creazione del gruppo è in userfactory. dove avviene l'interazione db della creazione di gruppo? in un repository di gruppo o in un repository utente? –

+0

Dipende. Potrebbe esserci un caso per un repository di gruppo. In pratica, prova a limitare gli archivi a uno per radice aggregata. In tal caso, utilizzare un GroupRepository per trovare un gruppo esistente e passare il gruppo come parametro nel metodo UserFactory.CreateNewUser. Quando UserRepository salva l'utente, controlla la configurazione per assicurarti di salvare anche l'associazione di gruppo. –

+1

In alternativa, potrebbe essere più opportuno creare un'istanza di un nuovo oggetto Utente e disporre di un metodo UserServices.RegisterWithDefaultGroup (Utente utente) con la seguente implementazione: Gruppo defaultGroup = _groupRepository.FindByName ("Default"); user.AddGroup (DefaultGroup); Registrati (utente); Dipende tutto dalla tua applicazione, dall'architettura del software e da quanto severi desideri aderire a determinati principi. In bocca al lupo! –

6

Personalmente, tengo il pattern del repository come sostituto per sprocs. Quindi il mio repository avrebbe metodi come getById(int id), save(), add(DomainObject obj) ecc

In un business di livello, mi piacerebbe avere userManager.registerUser (string username,/* params, etc * /). Questo creerebbe l'oggetto dominio. Questo metodo chiama semplicemente il metodo add() nel livello dati.

In breve, il livello aziendale è business-y e il livello dati è dati-y.

+0

In base ai nomi dei tuoi metodi, direi che i tuoi "repository" effettivamente seguono il modello "data mapper" dal libro Fowlers PofEAA. Un repository di Domain Driven Design è un'interfaccia simile a una raccolta piuttosto che una classe con metodi specifici. – jrista

3

Qual è la tua motivazione per l'utilizzo del modello di repository in primo luogo? Di solito, il repository è l'astrazione della logica di persistenza dell'oggetto. Recupera elementi da (di solito) un database e gestisce anche aggiornamenti, inserimenti ed eliminazioni.

Se stavate scrivendo un test per controllare un po 'di logica e non volevate colpire il database quali oggetti dovreste prendere in giro? Di solito il repository.

Nello scenario A) non è possibile testare un nuovo utente creato con i dati predefiniti corretti senza toccare direttamente il database.Per questo motivo, sosterrei mantenendo tutte le logiche di business al di fuori dei repository e seguo il tuo secondo progetto

+0

Un repository non dovrebbe gestire gli aggiornamenti. Dovrebbe astrarre l'accesso al database (o altra persistenza) in un'interfaccia come la raccolta. Una normale raccolta di dotnet come un elenco o un dizionario non ha bisogno di sapere degli aggiornamenti. Neanche un repository. – Paco

0

Vedo due potenziali problemi di "torto" (dal momento che non hai davvero indicato cosa pensavi fosse sbagliato con loro).

  1. Se il problema ruota attorno il salvataggio del gruppo nel metodo di registrazione utente, o il salvataggio l'utente nei metodi di gruppo, allora si dovrebbe separare questi in diversi metodi. (ad esempio Register() chiamerebbe RegisterGroup() o GetGroup()

  2. Se il problema ruota attorno al salvataggio di cose prima che l'utente sia veramente pronto per salvare concettualmente le cose, quindi tenere traccia di ciò che volevano aggiungere e attendere fino a quando il nel complesso "salvare" metodo viene chiamato prima di mettere qualsiasi di queste informazioni in deposito.

1

Dall'esempio del codice, chiamerei il metodo Register un'operazione di servizio. Come operazione di servizio, dovrebbe appartenere a un servizio o a un componente aziendale anziché a un repository. Secondo Evans (di fama DDD), un repository è un'interfaccia simile a una raccolta di entità memorizzate nel database. L'idea generale è che tu fornisca un accesso di tipo CRUD di base alle tue entità attraverso un repository per astrarre il resto del tuo codice dai dettagli di accesso ai dati di livello inferiore come uno strumento ORM.

Per il tuo esempio con Registra ... il tuo metodo di servizio dovrebbe convalidare l'input, creare l'oggetto User e quindi chiamare il tuo repository su "Aggiungi" la tua nuova entità al "repository" (che potrebbe essere un database ... ma potrebbe anche essere qualcos'altro ... per quanto riguarda il tuo dominio, non importa ... è solo un repository.)

+0

L'operazione di servizio all'interno di una classe controller o nel livello aziendale? O è la stessa cosa che ti preoccupa in questo caso? –

+0

Bene, considero i controllori diversi dai servizi. Un controller è un punto di accesso per l'interazione umana ...e in generale, dovrebbero essere il più leggeri possibile. I controllori dovrebbero eseguire un'orchestrazione minima delle chiamate verso altri servizi, impacchettare tutti i dati e indirizzare tali dati a una vista, niente di più. Un servizio può essere un servizio applicativo o un servizio aziendale. I servizi applicativi possono eseguire un lavoro a livello di applicazione puramente o comporre più servizi aziendali ... ma un servizio è il luogo in cui risiede la maggior parte del tuo comportamento, compreso l'uso di repository. – jrista

+1

@ Bear Bear: Scopri l'architettura della cipolla di Jeffrey Palermo. Questo è quello che uso per le app in stile DDD. Può aiutare a spiegare cosa va Dove. In bocca al lupo! http://jeffreypalermo.com/blog/the-onion-architecture-part-1/ –

Problemi correlati