Alessandro Del Sole's Blog

{ A programming space about Microsoft® .NET® }
posts - 1908, comments - 2047, trackbacks - 352

My Links

News

Your host

This is me! Questo spazio è dedicato a Microsoft® .NET®, di cui sono molto appassionato :-)

Cookie e Privacy

Disabilita cookie ShinyStat

Microsoft MVP

My MVP Profile

Microsoft Certified Professional

Microsoft Specialist

Xamarin Certified Mobile Developer

Il mio libro su VB 2015!

Pre-ordina il mio libro su VB 2015 Pre-ordina il mio libro "Visual Basic 2015 Unleashed". Clicca sulla copertina per informazioni!

Il mio libro su WPF 4.5.1!

Clicca sulla copertina per informazioni! E' uscito il mio libro "Programmare con WPF 4.5.1". Clicca sulla copertina per informazioni!

These postings are provided 'AS IS' for entertainment purposes only with absolutely no warranty expressed or implied and confer no rights.
If you're not an Italian user, please visit my English blog

Le vostre visite

I'm a VB!

Guarda la mia intervista a Seattle

Follow me on Twitter!

Altri spazi

GitHub
I miei progetti open-source su GitHub

Article Categories

Archives

Post Categories

Image Galleries

Privacy Policy

Utilizzo di stored procedure in ADO.NET Entity Framework con VB 2008

Piccola premessa: ben accetti consigli al termine del post soprattutto da chi ha esperienze pratiche con Entity Framework (Davide, Andrea, Corrado, Andrea due, Stefano se passate di qua date un’occhiata!). Sicuramente in questo post troverete cose che da altre parti, anche autorevoli, non sono state dette e non so perchè.

 

Nel mio libro su LINQ in Visual Basic 2008, ho trattato in modo abbastanza completo LINQ-to-SQL mentre nel capitolo dedicato ad ADO.NET Entity Framework e LINQ to Entities ho preferito fare un’overview introduttiva del discorso con esempi ridotti, poiché, al momento della scrittura del libro, la release disponibile era la Beta 3 e molte cose sarebbero cambiate con il rilascio definitivo di .NET 3.5 SP 1.

 

Quindi sto approfondendo un po’ ciò che riguarda l’Entity Framework, anche per riproporre in questa chiave qualche esempio del libro, e mi sono trovato ad affrontare la problematica delle stored procedure. Premetto che non mi sono ancora fermato dall’approfondire questo argomento importante, tuttavia vi riporto l’esperienza che ho avuto e devo dire che alcune cose non mi hanno entusiasmato, ma probabilmente, come detto, l’ulteriore approfondimento e i consigli di chi è più esperto mi smentiranno.

 

Partiamo con una demo in Visual Basic 2008, nella quale vogliamo utilizzare una stored procedure disponibile nel database Northwind. Per lo scopo e per velocità, creiamo un progetto Windows Forms. Stabiliamo una connessione al database in questione e aggiungiamo un Entity Data Model, che si chiamerà Northwind.edmx, con le modalità già note. Nella finestra di selezione dei dati da mappare, selezioniamo le tabelle Customers, Orders e Order Details, quindi espandiamo la voce Stored Procedures e selezioniamo la procedura chiamata CustOrdersOrders, che restituisce gli ordini effettuati dal cliente specificato:

 

 

Dopo alcuni secondi dal termine della procedura guidata, il designer OR/M di Entity Framework ci mostra le entità desiderate. Per aggiungere al modello una stored procedure, facciamo clic destro in una qualunque parte del designer e, dal menu contestuale, selezioniamo il comando Add, quindi Function Import come in figura:

 

 

Questa operazione attiverà la finestra Add Function Import, nella quale va selezionata la stored procedure di interesse (nel nostro caso ce n’è una sola), specificato l’identificatore e il tipo di dato da restituire:

 

 

Possiamo specificare una scalar property, un’entità oppure nessun tipo. Nel nostro caso selezioniamo l’entità Orders e facciamo clic su OK. Nel file di code-behind dell’EDM, Visual Studio ha generato del codice Visual Basic per la nostra funzione, che dipende dalla classe NORTHWNDEntities, che è il seguente:

 

    Public Function CustOrdersOrders(ByVal customerID As String) As Global.System.Data.Objects.ObjectResult(Of Orders)

        Dim customerIDParameter As Global.System.Data.Objects.ObjectParameter

        If (Not (customerID) Is Nothing) Then

            customerIDParameter = New Global.System.Data.Objects.ObjectParameter("CustomerID", customerID)

        Else

            customerIDParameter = New Global.System.Data.Objects.ObjectParameter("CustomerID", GetType(String))

        End If

        Return MyBase.ExecuteFunction(Of Orders)("CustOrdersOrders", customerIDParameter)

    End Function

 

Il metodo ExecuteFunction dell’ObjectContext è quello che effettivamente esegue la stored procedure sull’origine dati. Tutto questo si traduce quindi in un normale metodo .NET chiamato CustOrdersOrders, che compare anche nella finestra Model Browser:

 

 

Ora, prima osservazione: se avessi invece voluto utilizzare la procedura CustOrdersDetail, che in LINQ-to-SQL restituisce un tipo CustOrderDetailsResult, come posso fare dato che il designer mi consente di scegliere come tipo restituito solo entità o scalar properties? Prima domanda a cui dalle ricerche finora svolte non ho trovato risposta... ma, ripeto, non mi sono fermato. J

 

Molto bene, ora passiamo al designer Windows Forms e aggiungiamo un BindingSource (OrdersBindingSource), un BindingNavigator (OrdersBindingNavigator) e una DataGridView (OrdersDataGridview), quindi personalizziamo il BindingNavigator aggiungendo una Label, una TextBox (CustomerIdTextBox) e un pulsante (SearchButton). Il tutto deve comparire così:

 

 

Ora passiamo al codice Visual Basic e scriviamo il seguente codice di inizializzazione:

 

    Private northwind As NORTHWNDEntities

 

    Public Sub New()

 

        ' This call is required by the Windows Form Designer.

        InitializeComponent()

 

        ' Add any initialization after the InitializeComponent() call.

 

        northwind = New NORTHWNDEntities

    End Sub

 

e facciamo in modo che, al clic sul pulsante, venga recuperate l’ID cliente specificato e passato alla stored procedure, o meglio al nostro metodo mappato CustOrdersOrders il cui risultato alimenterà la DataGridView:

 

    Private Sub SearchButton_Click(ByVal sender As System.Object, _

                                   ByVal e As System.EventArgs) Handles SearchButton.Click

 

        If String.IsNullOrEmpty(CustomerIdTextBox.Text) = False Then

 

            OrdersDataGridView.AutoGenerateColumns = True

            OrdersBindingSource.DataSource = northwind.CustOrdersOrders(CustomerIdTextBox.Text)

 

        End If

    End Sub

 

Avviamo l’applicazione, digitiamo un ID cliente nel campo apposito e facciamo clic sul pulsante di ricerca. Risultato:

 

 

Scoraggiante, ve lo assicuro.. soprattutto perchè in LINQ to SQL questo non sarebbe accaduto. Dopo molte ricerche e diverse “intuizioni”, ho scoperto che ci deve essere esatta corrispondenza tra le scalar properties delle entità e i dati estrapolati dalla stored procedure. In altre parole, la stored procedure in questione esegue una query che estrae il valore solo di alcune colonne nella tabella Orders, ma affinché ci sia corrispondenza con l’EDM deve estrarre il valore di tutte le colonne. Vado quindi in Database Explorer (ho usato Visual Basic Express), espando la struttura del db, raggiungo la stored procedure incriminata, faccio clic destro e seleziono il comando Open per visualizzarne il codice, come in figura:

 

 

Una volta che Visual Studio mostra il codice SQL della stored procedure, faccio clic destro all’interno del riquadro blu e seleziono Design SQL Block. Nella finestra Query Builder, seleziono tutte le colonne per la tabella Orders e automaticamente il codice SQL viene aggiornato:

 

 

Salvo i cambiamenti al db (passaggio da non dimenticare), quindi devo aggiornare l’Entity Data Model eseguendo nuovamente il mapping della stored procedure. A tal proposito ho utilizzato il comando Update model facendo clic destro nella finestra Model Browser che compare a fianco di Solution Explorer ogni qualvolta attivate il designer OR/M.

 

Eseguo nuovamente la mia applicazione, digito un Customer ID e finalmente il risultato è quello sperato:

 

  

In questo modo, però, la DataGridView conterrà tutte le colonne estratte dalla stored procedure. Se ne volessimo escludere qualcuna a runtime, come fatto dalla stored procedure originaria, dovremmo eseguire una query LINQ sul risultato della procedura stessa.

 

Una cosa è certa: LINQ to SQL in questo senso è decisamente più comodo, pur con i suoi altri limiti. Vediamo i successivi approfondimenti sull’argomento (e spero i feedback di qualcuno di voi) quali considerazioni ci porteranno a fare.

 

Alessandro

Print | posted on martedì 6 gennaio 2009 22:20 | Filed Under [ Visual Basic LINQ ]

Powered by:
Powered By Subtext Powered By ASP.NET