ciao,
AdeptusAstartes ha scritto:
la proprietà Descrizione del mio controllo posso gestirla come proprietà o è meglio usare un metodo modificaDescrizione()?
Dato che la Descrizione non è coinvolta nella logica di business ti direi di usare il setter e basta. Ad oggi avrebbe senso creare un metodo wrapper solo se intendi creare una task-based UI, cioè se mostri una specifica maschera all'utente in cui può modificare giusto titolo e descrizione. Al salvataggio invocheresti il metodo .AggiornaTesti(string titolo, string descrizione) oppure .AggiornaTesti(Testi testi) se decidessi di accorpare titolo e descrizione in un value type.
AdeptusAstartes ha scritto:
posso gestirla come proprietà
Comunque, la domanda non deve essere "posso farlo?" perché puoi indubbiamente fare tutto quello che vuoi.
Tra le abilità di uno sviluppatore non è tanto importante la sua capacità di evitare - oggi - ogni eventuale errore, perché è impossibile fare previsioni accurate sul come matureranno i requisiti di business nel futuro. Anzi, chi cerca di prevedere ogni situazione possibile spesso cade nella trappola dello
YAGNI.
L'abilità invece sta nel capire e nell'avere la volontà di fare refactoring quando un problema si manifesta.
Se domani ti chiedessero: "Vorrei che la descrizione supportasse gli hashtags come Twitter. Ovvero, ogni qualvolta scrivo il simbolo # seguito da una parola, vorrei che automaticamente sia legato un tag che posso trovare dal box di ricerca."
In quel caso, un buono sviluppatore, non si lascerebbe influenzare dal fatto che, tanto ormai, ha usato il setter ma capirebbe che quella è una responsabilità dell'entità e che perciò la logica va incapsulata in un suo metodo.
AdeptusAstartes ha scritto:
DL) progetto class library che dovrebbe racchiudere la definizione delle mie entità
BL) progetto class library con la logica di dominio
Che intendi con "logica di dominio"? Parte della logica sarà nelle classi di entità e parte in servizi di dominio (es. la factory dei Controlli), che secondo me dovrebbero trovarsi anche loro nello stesso progetto.
Forse intendi l'
application layer, un livello che adatta le classi di dominio secondo i casi d'uso. Puoi metterci i ViewModel e tutto ciò che riguarda i
cross-cutting concerns, tipo logging e sicurezza.
AdeptusAstartes ha scritto:
DAL) progetto class library in cui vorrei racchiudere EF
Ok, metti in quel progetto tutti i servizi infrastrutturali. Non solo EF ma anche il servizio che spedisce email, che accede al filesystem, e così via.
AdeptusAstartes ha scritto:
Mi serve quindi creare la classe Status ma tutta la logica dovrei gestirla nel mio oggetto Controllo all'interno del Domainlayer senza quindi posticipare il tutto a quando andrò a creare il BL?
Sì, in Controllo hai già creato la tua lista di Status quindi non devi fare altro che aggiungere un elemento a quella lista ogni qualvolta vengono invocati i metodi Completa(), Abbandona(), Sospendi(), ecc..
Se lo storico degli status è un qualcosa di cui parleresti agli esperti di dominio (cioè te l'ha chiesto il committente di poter vedere l'esito degli stati) allora ha senso che quella logica sia nella classe di entità Controllo.
Se invece si trattasse di un requisito non funzionale (cioè logghi i cambi di stato giusto per poter ricostruire la situazione in un certo punto nel tempo) allora probabilmente è un qualcosa che dovresti mettere nell'application layer.
La classe Controllo dovrebbe limitarsi a sollevare un
evento di dominio che verrebbe poi recapitato al servizio che logga i cambi di stato.
AdeptusAstartes ha scritto:
devo quindi prevedere nell'oggetto i metodi crea(), modifica() ed elimina()
No, le classi di dominio devono essere
persistent-ignorant. Come hai detto tu, questi metodi appartengono al progetto dei servizi infrastrutturali.
Se decidi di usare il pattern repository, ha senso mettere l'interfaccia IRepostitory<T> dentro il progetto di dominio (ad esempio se qualche servizio di dominio dovesse aver bisogno di accedere al db), e là puoi letteralmente chiamare quei metodi Modifica(T entità) o Elimina(T entità). L'implementazione concreta di quell'interfaccia, però, andrebbe inserita nel progetto dei servizi infrastrutturali.
AdeptusAstartes ha scritto:
voglio gestire un progressivo come chiave ma gestito da me e non dal db per avere maggiore flessibilità, devo quindi trovare il max presente in tabella e aggiungere 1, ma dove metto questa logica?
In un servizio di dominio. Il servizio, come parte di un'unica transazione, accederà al database per ottenere il numero massimo ed incrementarlo di 1, poi assegnerà questo numero al Controllo e lo persisterà nel database.
Trovi un caso assimilabile al tuo a questo indirizzo:
http://gorodinski.com/blog/2012/04/14/services-in-domain-driven-design-ddd/Lì viene posto l'esempio di un IInvoiceNumberGenerator che serve a generare il numero per una fattura.
AdeptusAstartes ha scritto:
L'interfaccia chiama la sua Facade nel BL
Dal BL smisto le chiamate verso DAL e DL ma come? Devo sapere cosa c'è da una parte (persistenza) e cosa dall'altra (logica)?
Mah, trattandosi di MVVM immagino che l'interfaccia invochi un comando nel ViewModel. Quest'ultimo avrà una dipendenza da un IRepository<Controllo> e perciò il container IoC, durante la costruzione, gli avrà iniettato un'implementazione concreta che si trova nel progetto dei servizi infrastrutturali. Il ViewModel a questo punto recupererà un'entità per mezzo di quel repository e poi invocherà un metodo sull'entità (es. Completa(Esito esto)). Infine chiamerà il metodo Modifica(entità) del repository, il quale farà in modo che l'entità venga persistita nel database.
AdeptusAstartes ha scritto:
Ma la factory sarebbe unica per tutto il progetto? E in quale progetto: DL o BL?
No, ogni factory dovrebbe avere una singola responsabilità. Quella di cui abbiamo parlato serviva a costruire le entità Controllo. Poi ci saranno altri servizi di dominio, come quello che ti genera i progressivi di cui abbiamo parlato prima.
Queste classi andrebbero inserite nel progetto di dominio.
AdeptusAstartes ha scritto:
Per le tabelle esterne mi viene in mente questa soluzione: sul db dell'applicazione creo una query che estrae paro paro la tabella esterna e mappo questa con EF.
Sì, puoi crearti una vista che selezioni i dati dall'altra tabella.
In alternativa puoi anche provare la strada dei
sinonimi ma non l'ho mai fatto e non so se funziona con EF4. Dovresti provare.
AdeptusAstartes ha scritto:
L'unico inconveniente che ci vedo è che usando CodeFirst per creare il db mi ritroverò con una tabella che dovrò eliminare per creare successivamente una vista con lo stesso nome.
Puoi crearti un
database initializer personalizzato. Là metterai la logica per creare le viste (o i sinonimi).
ciao,
Moreno