24 messaggi dal 16 febbraio 2007
Ciao a tutti, spero di non essere OT e spero che le mie domande non risultino eccessivamente banali o "stupide".

Devo iniziare la realizzazione di un progetto di piccole/medie dimensioni.
La "tipica" applicazione web che inserisce, modifica, ricerca e cancella dati archiviati in un db.

Prima di metterci mano mi sono chiesto quale sarebbe la struttura migliore e il miglio approccio per la realizzazione. Documentandomi ho avuto conferma che la struttura 3-tier è la struttura migliore.
Ma a questo punto mi vengono alcune domande, che spero troveranno risposta.

1) Per gestire i dati (archiviati in un db di sql express 2005) è meglio creare delle stored procedure? Oppure è meglio creare dei comandi insert, update, select e delete direttamente nel progetto? Indicando ad esempio direttamente il comando "insert into tabella ..." nalla dll della data layer?

2) La struttura n-tier comporta un maggiore investimendo di tempo durante la fase di realizzazione. Che vantaggi porta praticamente?

3) La struttura n-tier, per essere implementata al meglio come dev'essere strutturata?
Un livello deve occuparsi di gestire la presentazione all'utente, uno deve gestire la business logic e uno deve interagire con la base dati. Quali sono gli eventuali accorgimenti da tener presente?
Ammesso ad esempio di voler gestire una classe Persona con le property Nome e Cognome. Sarebbe corretto creare una dll che contiene la definizione della classe referenziata in tutti i livelli (presentation, business e data layer)? In questo modo quando l'utente compila i dati nel webform viene creata una nuova istanza della classe Persona e vengono valorizzate le property Nome e Cognome. Successivamente questa istanza viene passata al business layer che la valida e, se l'istanza è considerata valida e corretta, viene passata alla data layer che si occupa della scrittura nel database.

Spero di essere stato abbastanza chiaro.
Ringrazio tutti quelli che vorranno chiarire i miei dubbi.

Grazie

Luca
69 messaggi dal 20 gennaio 2006
www.jntstudio.net
Creare delle buone architetture fa in modo che il codice che scrivi non sia fine a se stesso ma sia espandibile, manutentibile, flessibile... questi sono tra gli aggettivi che vengono utilizzati più frequentemente.

Per quanto riguarda il primo punto, se hai deciso che vale la pena implementare un architettura 3 tyer, opterei per la creazione di Stored Procedure: oltre al fatto che SQL server dopo averle eseguite la prima volta le ottimizza e le tiene in memoria fornendo indubbi vantaggi in termini di prestazioni, otterrai un ottima separazione con il livello soprastante e renderai possibili e semplici futre modifiche.
A livello DataAccessLayer puoi anche decidere di implementare un architettura ProviderModel creando una classe astratta con l'elenco dei metodi e poi una serie di provider, ad esempio il provider SQL, che fanno l'ovverride dei metodi virtual della classe abstract, crei una customSection nel web.config e la usi anche per salvare il tipo di provider che utilizzi. In questo modo, se un giorno decidi di passare a MySql ad esempio, dovrai solo aggiungere questo provider e cambiare una riga nel web.config.

A livello BLL, ad esempio, si fa il controllo sui dati, si "adattano i dati da passare alla User Interface"... ad esempio se nel database devi salvare un numero che rappresenta una temperatura, a questo livello formatterai il valore in modo che abbia senso nella UI.
In BLL c'è molto lavoro da fare per ottimizzare le prestazioni: qui ad esempio si implementano i vari meccanismi di CACHING in modo da evitare gli inutili accessi diretti al database per ogni richiesta...
Se hai nel database un elenco di articoli ed hai un metodo a livello DAL che restituisce gli articoli di una determinata categoria, alla prima richiesta, a livello BLL, accedi al database, recuperi i valori, crei una sezione nella cache dove metti i valori recuperati, e li passi alla UI.
Alle successive richieste, a livello BLL, prima di accedere a DAL controlli che la cache non sia vuota per la chiave "articoli per una determinata categoria". Se la cache non è vuota recuperi i valori direttamente da li.
Poi nei metodi che inseriscono un nuovo articolo o ne cancellano uno, a livello BLL ti occuperai anche di cancellare la cache in modo che il metodo precendente che recupera l'elenco degli articoli per una determinata categoria, riacceda alla sorgente dati e ricrei la cache aggiornata.

Altra cosa che si implementa a livello BLL e sulla quale ti consiglio di documentarti è il LazyLoading ovvero, tornando all'esempio degli articoli, il corpo dell'articolo non ti serve da visualizzare negli elenchi ma solo nei dettagli quindi farai un paio di override dei metodi che restituiscono gli articoli: uno che restituisce anche il corpo e uno che non lo carica neanche in memoria... questo detto rapidamente e banalmente: comunque è un argomento molto comune e non ti sarà difficile reperire informazioni.

Già con queste poche cose che ho illustrato credo siano evidenti i vantaggi che si hanno al prezzo di una maggiore fatica: prestazioni, manutentibilità, espandibilità, flessibilità.

JackNova (Dario Iacampo)
24 messaggi dal 16 febbraio 2007
Innanzitutto grazie per la risposta, chiara e precisa.
Sicuramente approfondirò il caching e il LazyLoading.

Vorrei ancora un chiarimento.

Data una tabella Persone con i campi Nome, Cognome e Telefono vorrei creare una stored, da richiamare nel progetto web, a cui voglio passare i parametri @Nome, @Cognome e @Telefono.
Il fatto è che tutti i parametri sono opzionali, ossia l'utente ha la facoltà di specificarne uno, tutti o nessuno.
Nel caso in cui vengano valorizzati tutti i parametri non ci sono problemi, nel caso in cui non lo siano il select deve considerare solo quelli valorizzati.

L'unica soluzione che ho trovato è questa (spero che qualcuno possa darmi soluzioni più valide)

Esempio:

Create Procedure PersoneSelect
(
@Nome varchar(50) = null ,
@Cognome varchar(50) = null ,
@Telefono varhcar(20) = null
)
as

declare @Sql varchar(1000)
set @Sql = ''

if (@Nome <> '') set @Sql = ' Nome = ''' + @Nome + ''' and '
if (@Cognome <> '') set @Sql = ' Cognome = ''' + @Cognome + ''' and '
if (@Telefono<> '') set @Sql = ' Telefono= ''' + @Telefono+ ''' and '

set @Sql = ltrim(rtrim(@Sql))

if (@Sql <> '') set @Sql = ' where ' + left(@Sql, len(@Sql) -3)

set @Sql = 'select * from vwPersone ' + @Sql

exec(@Sql)

In questo modo tutto funziona, ossia, se l'utente imposta il valore per il parametro @Nome la store considera solo quel parametro ignorando cognome e telefono. Questo però non mi sembra molto performante, mi chiedevo se qualcuno ha soluzioni alternativi più performanti e "corrette".

Grazie

Luca
69 messaggi dal 20 gennaio 2006
www.jntstudio.net
Per nome e cognome ti consiglio di usare nvarchar anziché varchar.


la SP sarebbe più o meno così:

Create Procedure PersoneSelect
(
@Nome nvarchar(50) = NULL,
@Cognome nvarchar(50) = NULL,
@Telefono varhcar(20)= NULL
)
AS
SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
SELECT
*
FROM
Persone
where ((@Nome is null) or (Nome = @Nome))
and ((@Cognome is null) or (Cognome= @Cognome))
and ((@Telefono is null) or (Telefono = @Telefono ))


Modificato da bacco82 il 14 aprile 2008 17.32 -

JackNova (Dario Iacampo)
24 messaggi dal 16 febbraio 2007
Grazie Bacco82 per la risposta, ho ancora qualche "problemino".

Ho provato a "simulare" l'esempio che mi hai dato in questo modo. Molto grezzamente ho unito la bll e la dal. Ho inserito in un unico metodo la verifica dei parametri (bll) e la chiamata al db (dal).

Sotto inserisco il codice di test che ho usato.

using (SqlConnection cn = new SqlConnection(cnString))
{
SqlCommand cmd = new SqlCommand("PersoneSelect", cn);
SqlDataAdapter da;
DataTable dt=new DataTable();

if (string.IsNullOrEmpty(nome))
nome = "*";

if (string.IsNullOrEmpty(cognome))
cognome = "*";

if (string.IsNullOrEmpty(telefono))
telefono = "*";

cmd.CommandType= System.Data.CommandType.StoredProcedure;
cmd.Parameters.Add("@Nome", SqlDbType.NVarChar).Value = nome;
cmd.Parameters.Add("@Cognome", SqlDbType.NVarChar).Value = cognome;
cmd.Parameters.Add("@Telefono", SqlDbType.VarChar).Value = telefono;
cn.Open();

da = new SqlDataAdapter(cmd);
da.Fill(dt);
}


il problema è che, nonostante abbia popolato la tabella con dei dati di test, non mi vengono restituiti dati quando passo i parametri string.empty.

Non è che nella stored devo usare il like al posto dell'uguale e nella bll invece che usare * devo usare %? In pratica andrei a fare dei like (che credo siano meno performanti).

Spero di essere stato sufficientemente chiaro.

Luca
Modificato da caluse il 14 aprile 2008 16.39 -
69 messaggi dal 20 gennaio 2006
www.jntstudio.net
fatto un terribile errore prima :-O
ho modificato il post.
Quella è una soluzione: praticamente con gli OR separati da AND se un parametro è a NULL non viene presa in considerazione tutta la riga: dovrebbe funzionare bene.

tieni presente che quella soluzione non funziona se qualche valore nel database è NULL e ANSI_NULLS è ON.

Ci sono anche delle soluzioni alternative, ad esempio

SELECT *
FROM Persone
WHERE nome = COALESCE(@nome, nome) AND
cognome = COALESCE(@cognome, cognome) AND
telefono = COALESCE(@telefono , telefono )

a questo indirizzo trovarei delle informazioni certamente più esaustive che ti aiuteranno a comprendere meglio la situazione: http://www.sommarskog.se/dyn-search.html

JackNova (Dario Iacampo)
24 messaggi dal 16 febbraio 2007
Grazie x il link.

Ora approfondierò l'argomento, in ogni caso non esiste, in pratica, un sistema "diretto" (passami il termine) per fare il select utilizzando alcuni dei possibili parametri. Ad una prima occhiata ho visto che usa il concatenamento di un comando sql o la stored di sistema sp_executesql.
Resta comunque l'alternativa che hai postato prima.

Ora faccio qualche test e poi faccio sapere che sistema userò, magari sarà utile ad altri.

Grazie

Luca

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.