buongiorno, benvenuto nel forum!
Provo a rispondere a tutte le due domande.
AdeptusAstartes ha scritto:
per varie ragioni i nomi delle tabelle e dei campi presenti nel DB sono diverse dai nomi che gli oggetti e le proprietà dovranno avere nell'applicazione: è facilmente gestibile?
Certo, dal designer puoi facilmente cambiare i nomi di tabelle e campi.
Questo è possibile perché nel
data model di Entity Framework, lo
schema dello storage (composto di tabelle, campi, relazioni e SP) sono debolmente accoppiati con il
modello concettuale (classi, proprietà, associazioni e funzioni). Tra loro esiste un livello di
mapping che rende possibili varie cose.
- Cambio dei nomi
- Rifattorizzazione di alcuni campi in un tipo complesso. Ad esempio: se nella tabella Ordine hai i campi Via, Città, Provincia e Comune, questi possono essere raggruppati logicamente in un tipo complesso chiamato "Indirizzo" che puoi usare come proprietà dell'entità Ordine.
- Ereditarietà. Entity Framework ti consente di riappropriarti di uno dei pilastri della programmazione orientata agli oggetti. Le entità (classi) che hai nel modello concettuale, non devono per forza rimappare 1:1 con tabelle del database. Puoi creare più entità derivate che rimappano ad una singola tabella, in cui è presente un campo che funziona da discriminatore. Oppure puoi splittare una singola entità su più tabelle. Hai sufficiente spazio di manovra per creare un modello idoneo. Dopotutto tra i compiti di un ORM c'è quello di ridurre il conflitto di impedenza che esiste tra il modello relazionale e il modello orientato agli oggetti.
AdeptusAstartes ha scritto:
potrei anche pensare di lasciar fare le CRUD a EF
Sì, puoi lasciarglielo fare perché il DbContext di Entity Framework eseguirà i comandi UPDATE, INSERT e DELETE nel contesto di una transazione. Questo comportamento è perfetto anche quando stai salvando un'entità Ordine e le tutte le sue entità correlate LineaOrdine. Con una sola invocazione al metodo .SaveChanges del DbContext, tutte le entità verranno persistite e tu avrai la sicurezza che il database si troverà in uno stato consistente sia che l'aggiornamento abbia avuto successo sia che si sia verificato un errore.
AdeptusAstartes ha scritto:
ma molte logiche complesse vorrei lasciarle sul DB, so che EF permette di gestire le SP
Sì, verranno importate come funzioni nel DbContext. Inoltre, se vuoi, puoi mappare la SP all'operazione di Insert, Update o Delete di un'entità. EF invocherà la stored procedure anziché inviare l'opportuno comando al database.
AdeptusAstartes ha scritto:
per evitarne la proliferazione ho sempre fatto in modo da avere una sola SP per ogni tabella, a seconda di un parametro effettuo operazioni diverse e ritorno recordset diversi all'applicazione: è gestibile?
Comprendo la scelta, è una decisione molto "umana" quella di voler tenere tutto in ordine. In realtà, creando una sola SP per ogni tabella hai solo nascosto la polvere sotto al tappeto.
Se stai scrivendo un software di qualità, dovrai comunque documentare ogni operazione che ciascuna SP è in grado di fare, quindi il lavoro non sarà diminuito.
A spaventarti non dovrebbe essere il numero di stored procedure ma la loro cripticità, specie se le progetti in modo che restituiscano risultati diversi in base ai parametri in ingresso.
E' preferibile, secondo me, averne molte e molto semplici anziché averne poche ma più complesse. Anche se sono tante, potrai pur sempre organizzarle in schemi diversi. Il data model di Entity Framework infatti può lavorare con oggetti database provenienti da più schemi.
Chiediti questo: se il progetto dovesse passare in mano ad un altro sviluppatore, riuscirebbe subito a capire come usare le tue stored procedures o dovresti fornirgli assistenza?
Comunque, per rispondere alla tua domanda: quando importi una stored procedure nel designer di Entity Framework, devi anche indicare un tipo di ritorno che non può cambiare da caso a caso. Il C# è un linguaggio staticamente tipizzato.
Sei comunque libero di inviare query arbitrarie al database, e quindi anche di eseguire SP con determinati parametri. Leggi questo articolo, ti mostra come ottenere da una query SQL un elenco di entità oppure di un tipo a tua scelta (es. un elenco di stringhe).
http://msdn.microsoft.com/en-US/data/jj592907In questo modo però vai a mettere le mani nello storage mentre tu, avendo scelto di usare un ORM, dovresti teoricamente interrogare solo il modello concettuale.
AdeptusAstartes ha scritto:
inserimento/modifica/cancellazione inviata al db viene trasformata in un'operazione di modifica/aggiunta. Si può gestire tramite EF?
Sì, come dicevo poc'anzi potresti mappare 3 stored procedures alle operazioni Insert, Update e Delete dell'entità. Queste SP potrebbero compiere la modifica/aggiunta di cui parlavi.
In alternativa, potresti lasciare che EF invii liberamente i suoi comandi CUD e poi intercettare il comando nel database con un
TRIGGER INSTEAD OF. Così non dovrai perdere tempo a mappare ogni-singola-stored-procedure su ogni-singola-entità.
Mi sembra che l'uso di un trigger ti possa garantire una maggiore consistenza dei dati. Senza trigger, infatti, io potrei eliminarti dei record dalla tabella eseguendo una DELETE dal Sql Server Management Studio. Invece tu vuoi che nessun record vada perso ma che, casomai, il suo campo DataFine venga aggiornato.
AdeptusAstartes ha scritto:
Per evitare una proliferazione di metodi nel BL ho creato un singolo metodo strutturato così
Non serve, infatti puoi
proiettare un'entità su un tipo a tua scelta. Può trattarsi anche di un
tipo anonimo, cioè di un tipo creato dal compilatore e che non esiste nel tuo codice sorgente.
Ad esempio, volendo ottenere da un Ordine solo il Totale il numero di righe d'ordine, puoi usare il metodo .Select per
proiettare solo quelle due informazioni.
var contesto = new MioDbContext();
//estraggo solo i campi Totale e il numero di righe.
//la variabile risultato sarà un elenco di un tipo anonimo che ha solo le proprietà Totale e NumeroRighe.
var risultato = contesto.Ordini.Select(ordine=>new {ordine.Totale, NumeroRighe=ordine.RigheOrdine.Count()}).ToList();
contesto.Dispose();
//metto in binding il risultato
gridView.DataSource = risultato;
gridView.DataBind();
EF preparerà una SELECT SQL comprendente solo i campi che hai menzionato nella tua query. Così ottimizzerai il trasferimento dati tra il database server e il web server.
AdeptusAstartes ha scritto:
in ottica di ottenere performance migliori
Certo, fai bene a voler estrarre dal database solo i campi che ti servono. Comunque, anche se scegli Entity Framework, non sei obbligato ad usarlo in ogni situazione. Nei momenti in cui vuoi spremere il massimo delle prestazioni dai tuoi server, potresti addirittura leggere i dati con il DataReader di ADO.NET oppure usare un ORM molto più sottile come
dapper. Dipende dalle criticità del tuo sistema. Le prestazioni non devono comunque essere un'ossessione, altrimenti rischieresti di sacrificare la tua produttività nell'opinabile obiettivo di risparmiare qualche millisecondo.
AdeptusAstartes ha scritto:
EF può darmi dei benefici oppure il grado di personalizzazione che voglio ottenere richia di portarmi a scrivere ancora buona parte del codice a mano con in più dei vincoli alla flessibilità?
Sì, può indubbiamente portarti dei benefici ma solo tu puoi decidere se iniziare ad impegarlo in questo progetto. L'investimento di tempo necessario a riscrivere funzionalità già implementate con l'altro ORM, potrebbe non essere completamente ripagato.
In particolare pensa alle necessità dei tuoi utenti. Stanno aspettando con urgenza nuove funzionalità? In questo caso diventa rischioso fermarsi e farli aspettare che tu abbia cambiato architettura.
Se invece hai già rilasciato una prima versione del software e sei in fase di analisi di una seconda versione, allora potresti avere l'opportunità per pianificare una nuova architettura.
ciao, spero di esserti stato d'aiuto.
Moreno