- Extension method e ottimizzazione
dell'accesso ai database -
|
|||
COSA SERVE PER QUESTO TUTORIAL | |||
Download | Chiedi sul FORUM | Glossario | cognizioni basiche di VB .Net | ||
Come rendere aggiungere metodi a classi preesistenti | |||
GLI EXTENSION METHOD Come funziona l'attributo Extension. Con Visual Basic 2008 (e C# 3.0) tra le varie novità ve ne è una semplice da utilizzare, comoda ma soprattutto elegante. Si tratta degli "extension method", ovvero dei metodi (o più precisamente Sub e Function) che "estendono" le funzionalità di una classe, ovvero che potranno essere chiamate come se fossero metodi di quella classe. A designare la classe da estendere, e a dare un nome a quello che, se il metodo fosse definito all'interno della classe, sarebbe la variabile Me è il primo parametro che il metodo riceve. Ad esempio, mettiamo di voler scrivere una funzione che prenda una stringa e la restituisca con una lettera maiuscola e una minuscola alternatamente, normalmente la stenderemmo alla maniera seguente: Public Module ExtensionMethods Public Function ToLowerUpper(ByVal str As String) As String If str Is Nothing Then Return Nothing Dim result As String = String.Empty For C1 As Integer = 0 To result.Length - 1 If C1 Mod 2 = 0 Then result &= result.ToUpper Else result &= result.ToLower End If Next C1 Return result End Function End Module E verrebbe chiamato come segue: Dim miaStringa As String = "Mia stringa!" Console.WriteLine(ToLowerUpper(miaStringa)) Invece se aggiungiamo al metodo ToLowerUpper l'attributo Extension (definito nel namespace System.Runtime.CompilerServices) come segue: Imports System.Runtime.CompilerServices Public Module ExtensionMethods <Extension()> _ Public Function ToLowerUpper(ByVal str As String) As String ' [...] End Function End Module Nota: gli extension method possono essere definiti solamente
all'interno di moduli. Dim miaStringa As String = "Mia stringa!" Console.WriteLine(miaStringa.ToLowerUpper()) Console.WriteLine("Altra stringa".ToLowerUpper()) Per meglio comprendere l'utilità di questa nuova funzionalità creiamo alcuni utili extension method per utilizzare più comodamente System.Data. SEMPLIFICARE L'ACCESSO AD UN DATABASE Effettuare una query su un database (o comunque una fonte dati) è
un'operazione che viene svolta molto frequentemente, tuttavia le classi
del Framework .Net non sono molto coincise, infatti, una volta aperta
correttamente la connessione, bisogna creare un oggetto DbCommand (o
DbDataAdapter) passandogli la connessione, la stringa SQL, creare un
DataSet (o una DataTable) se necessario, impostare tutti i parametri e
infine chiamare il metodo per eseguire la query (DbCommand.ExecuteNonQuery
o DbDataAdapter.Fill). <Extension()> _ Public Function CreateCommand(ByVal Connection As IDbConnection, ByVal Statement As String) As IDbCommand Dim command As IDbCommand = Connection.CreateCommand() command.CommandText = Statement Return command End Function In questa prima versione i parametri non sono contemplati, e non
risulta pertanto molto utile, ci risparmia solamente una o due righe di
codice. Dim miaConnessione As IDbConnection = New OdbcConnection("Stringa di connessione") miaConnessione.Open() Dim mioComando As IDbCommand = miaConnessione.CreateCommand("INSERT INTO Users(Name) VALUES(""Paul"")") mioComando.ExecuteNonQuery() miaConnessione.Close() Nella versione in grado di gestire i parametri però dobbiamo definire una struttura tramite la quale descrivere i parametri (nome, tipo, valore e così via), la struttura DbParameter: Public Structure DbParameter Public _value As Object Public _name As String Public _dbType As DbType Public _size As Integer Private _parameterCount As Integer Public Sub New(ByVal Name As String, ByVal Value As Object, ByVal DbType As DbType, ByVal Size As Integer) _value = Value _dbType = DbType _name = Name _size = Size _parameterCount = 0 End Sub Public Sub New(ByVal Name As String, ByVal Value As Object) Me.New(Name, Value, GetDbType(Value), Nothing) End Sub Public Sub New(ByVal Name As String, ByVal Value As Object, ByVal DbType As DbType) Me.New(Name, Value, DbType, Nothing) End Sub Public Shared Function GetDbType(ByVal Value As Object) As DbType Select Case True Case TypeOf Value Is Int16 Return DbType.Int16 Case TypeOf Value Is Int32 Return DbType.Int32 Case TypeOf Value Is Int64 Return DbType.Int64 Case TypeOf Value Is String Return DbType.String Case TypeOf Value Is Byte() Return DbType.Binary Case Else Throw New ArgumentException("A parameter can be only an Int16, Int32, Int64, Byte[] or String", _ "Parameters") End Select End Function Public Function CreateParameter(ByVal Command As IDbCommand) As IDbDataParameter Dim parameter As IDbDataParameter = Command.CreateParameter parameter.DbType = _dbType parameter.Value = _value parameter.Size = _size If String.IsNullOrEmpty(_name) Then parameter.ParameterName = "p" & _parameterCount.ToString _parameterCount += 1 Else parameter.ParameterName = _name End If Return parameter End Function End Structure Il costruttore minimale di questa struttura riceve come parametri il
nome e il valore, il tipo viene dedotto da una semplice funzione (GetDBType)
che supporta alcuni basilari e comuni tipi di dato (interi, stringhe e
array di byte). <Extension()> _ Public Function CreateCommand(ByVal Connection As IDbConnection, ByVal Statement As String, _ ByVal ParamArray Parameters As DbParameter()) As IDbCommand Dim command As IDbCommand = Connection.CreateCommand() command.CommandText = Statement For Each parameter As DbParameter In Parameters command.Parameters.Add(parameter.CreateParameter(command)) Next parameter Return command End Function Ecco come chiamare la funzione: Dim miaConnessione As IDbConnection = New OdbcConnection("Stringa di connessione") Dim mioComando As IDbCommand miaConnessione.Open() mioComando = miaConnessione.CreateCommand("INSERT INTO Users(Name, Occupation) VALUES(?nome, ?occupazione)", _ New DbParameter("?nome", "Paul"), New DbParameter("?occupazione", "Direttore")) mioComando.ExecuteNonQuery() miaConnessione.Close() Un ultimo overload di CreateCommand ci permette di specificare direttamente il parametro, senza istanziare la struttura DbParameter esplicitamente, ma sott'intendendo un nome del parametro del tipo "?pN" (dove N è un numero crescente maggiore di 1) e il tipo, che verrà automaticamente dedotto dal costruttore minimale e quindi dalla funzione DbParameter.GetDBType: <Extension()> _ Public Function CreateCommand(ByVal Connection As IDbConnection, ByVal Statement As String, _ ByVal ParamArray Parameters As Object()) As IDbCommand Dim command As IDbCommand = Connection.CreateCommand() command.CommandText = Statement For C1 As Integer = 0 To Parameters.Length - 1 Dim parameter As Object = Parameters(C1) command.Parameters.Add(New DbParameter("?p" & (C1 + 1), parameter).CreateParameter(command)) Next C1 Return command End Function È quindi possibile utilizzarlo come segue: Dim miaConnessione As IDbConnection = New OdbcConnection("Stringa di connessione") miaConnessione.Open() Dim mioComando As IDbCommand mioComando = miaConnessione.CreateCommand("INSERT INTO Users(Name) VALUES(?p1)", "Paul") mioComando.ExecuteNonQuery() miaConnessione.Close() A questo punto possiamo fare un altro passo e definire il metodo
IDbConnection.Execute che in un sol passaggio crea ed esegue la query,
senza coinvolgere esplicitamente alcun IDbCommand: <Extension()> _ Public Sub Execute(ByVal Connection As IDbConnection, ByVal Statement As String, _ ByVal ParamArray Parameters As Object()) Connection.CreateCommand(Statement, Parameters).ExecuteNonQuery() End Sub Che potrà quindi essere utilizzata come segue: Dim miaConnessione As IDbConnection = New OdbcConnection("Stringa di connessione") miaConnessione.Open() miaConnessione.Execute("INSERT INTO Users(Name) VALUES(?p1)", "Paul") miaConnessione.Close() EXTENSION METHOD PER QUERY DI SELEZIONE Vediamo ora come usare qualche altro extension method che coinvolge
query di selezione che permette di riempire un DataSet, una
DataTable o
un semplice oggetto in una sola linea di codice. Dim miaConnessione As IDbConnection = New OdbcConnection("Stringa di connessione") miaConnessione.Open() miaConnessione.Execute("INSERT INTO Users(Name) VALUES(?p1)", "Paul") Dim dtResult As DataTable, dsResult As DataSet, lastId As Integer dsResult = miaConnessione.FillDataSet("SELECT * FROM Users WHERE Name = ?p1 AND Surname = ?p2", _ "Giovanni", "Rossi") dtResult = miaConnessione.FillDataTable("SELECT MessageID FROM Messages WHERE Author = ?autore", _ New DbParameter("autore", "Carlo", DbType.String)) lastId = miaConnessione.FillObject(Of Integer)("SELECT LAST_INSERT_ID()") miaConnessione.Close()
|
|||
<< INDIETRO | by VeNoM00 |