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

ADO.NET Data Services: utilizzare LINQ to SQL con Visual Basic 2008 - seconda parte

Nel precedente post dedicato all'utilizzo di LINQ to SQL con gli ADO.NET Data Services, abbiamo visto come creare un nuovo servizio e di cosa necessitino le entità per essere interrogate sia in query string che da codice gestito, ossia l'attributo DataServiceKey nell'ambito di classi parziali.

Quest'oggi vediamo cosa invece serve per eseguire delle operazioni di inserimento/modifica/eliminazione nei confronti del DataContext, punto di ingresso in LINQ to SQL.

Per prima cosa, i crediti. Il codice che mostrerò in questo post è una traduzione autorizzata da Andrew Conrad di Microsoft, che ha realizzato un'implementazione in C# di ciò che andremo a vedere e che ha reso disponibile sulla MSDN Code Gallery a questo indirizzo. Andrew ha acconsentito alla traduzione (e successiva pubblicazione) di una versione Visual Basic del medesimo codice.

Negli ADO.NET Data Services, i giochi si svolgono attraverso l'interfaccia IUpdatable, che permette di avere a disposizione dei metodi per puntare alle risorse esposte dal servizio e di eseguire nei loro confronti alcune operazioni classiche, come ad esempio il salvataggio dei dati. In altre parole, IUpdatable offre un'infrastruttura per l'invio di richieste di tipo Http POST.

Dobbiamo anche in questo caso dichiarare una classe parziale (in modo da non intaccare il codice autogenerato), questa volta per la nostra classe NorthwindDataContext che fa da riferimento al modello a oggetti. Ci sono alcune direttive Imports preliminari e l'implementazione di IUpdatable:

Imports System.Data.Services

Imports System.Data.Services.Common

Imports System.Data.Linq

Imports System.Reflection

Imports System.Data.Linq.Mapping

 

Partial Public Class NorthwindDataContext

    Implements IUpdatable

A questo punto l'IDE aggiungerà automaticamente le firme dei metodi richiesti dall'interfaccia. Il codice seguente, piuttosto lungo ma corredato da commenti XML per riprodurre fedelmente quanto proposto da Andrew Conrad, completa l'implementazione. Per non complicare troppo l'organizzazione del presente post, potete consultare questa pagina della documentazione ufficiale MSDN per avere una descrizione dei metodi utilizzati, mentre è possibile fare riferimento al contenuto dei commenti:

    ''' <summary>

    ''' Adds the given value to the collection

    ''' </summary>

    ''' <param name="targetResource">target object which defines the property</param>

    ''' <param name="propertyName">name of the property whose value needs to be updated</param>

    ''' <param name="resourceToBeAdded">value of the property which needs to be added</param>

    Public Sub AddReferenceToCollection(ByVal targetResource As Object, ByVal propertyName As String, _

                                        ByVal resourceToBeAdded As Object) _

                                        Implements System.Data.Services.IUpdatable.AddReferenceToCollection

        Dim pi As PropertyInfo = targetResource.GetType.GetProperty(propertyName)

        If pi Is Nothing Then

            Throw New Exception("Can't find property")

        End If

        Dim collection As IList = DirectCast(pi.GetValue(targetResource, Nothing), IList)

        collection.Add(resourceToBeAdded)

    End Sub

 

    ''' <summary>

    ''' Revert all the pending changes.

    ''' </summary>

    ''' <remarks></remarks>

    Public Sub ClearChanges() Implements System.Data.Services.IUpdatable.ClearChanges

        Throw New NotSupportedException

    End Sub

 

    ''' <summary>

    ''' Creates the resource of the given type and belonging to the given container

    ''' </summary>

    ''' <param name="containerName">container name to which the resource needs to be added</param>

    ''' <param name="fullTypeName">full type name i.e. Namespace qualified type name of the resource</param>

    ''' <returns>object representing a resource of given type and belonging to the given container</returns>

    Public Function CreateResource(ByVal containerName As String, ByVal fullTypeName As String) _

                                   As Object Implements System.Data.Services.IUpdatable.CreateResource

 

        Dim t As Type = Type.GetType(fullTypeName, True)

        Dim table As ITable = GetTable(t)

        Dim resource As Object = Activator.CreateInstance(t)

        table.InsertOnSubmit(resource)

        Return resource

 

    End Function

 

    ''' <summary>

    ''' Delete the given resource

    ''' </summary>

    ''' <param name="targetResource">resource that needs to be deleted</param>

    ''' <remarks></remarks>

    Public Sub DeleteResource(ByVal targetResource As Object) _

                              Implements System.Data.Services.IUpdatable.DeleteResource

        Dim table As ITable = GetTable(targetResource.GetType)

        table.DeleteOnSubmit(targetResource)

    End Sub

 

    ''' <summary>

    ''' Gets the resource of the given type that the query points to

    ''' </summary>

    ''' <param name="query">query pointing to a particular resource</param>

    ''' <param name="fullTypeName">full type name i.e. Namespace qualified type name of the resource</param>

    ''' <returns>object representing a resource of given type and as referenced by the query</returns>

    Public Function GetResource(ByVal query As System.Linq.IQueryable, ByVal fullTypeName As String) _

                                As Object Implements System.Data.Services.IUpdatable.GetResource

        Dim resource As Object = query.Cast(Of Object).SingleOrDefault()

 

        ' fullTypeName can be null for deletes

        If fullTypeName IsNot Nothing AndAlso resource.GetType.FullName <> fullTypeName Then

            Throw New Exception("Unexpected type for resource")

        End If

        Return resource

    End Function

 

    ''' <summary>

    ''' Gets the value of the given property on the target object

    ''' </summary>

    ''' <param name="targetResource">target object which defines the property</param>

    ''' <param name="propertyName">name of the property whose value needs to be updated</param>

    ''' <returns>the value of the property for the given target resource</returns>

    Public Function GetValue(ByVal targetResource As Object, ByVal propertyName As String) _

                             As Object Implements System.Data.Services.IUpdatable.GetValue

        Dim table As MetaTable = Mapping.GetTable(targetResource.GetType)

        Dim member As MetaDataMember = table.RowType.DataMembers.Single(Function(x) x.Name = propertyName)

        Return member.MemberAccessor.GetBoxedValue(targetResource)

    End Function

 

    ''' <summary>

    ''' Removes the given value from the collection

    ''' </summary>

    ''' <param name="targetResource">target object which defines the property</param>

    ''' <param name="propertyName">name of the property whose value needs to be updated</param>

    ''' <param name="resourceToBeRemoved">value of the property which needs to be removed</param>

    Public Sub RemoveReferenceFromCollection(ByVal targetResource As Object, ByVal propertyName As String, _

                                             ByVal resourceToBeRemoved As Object) _

                                             Implements System.Data.Services.IUpdatable.RemoveReferenceFromCollection

        Dim pi As PropertyInfo = targetResource.[GetType]().GetProperty(propertyName)

        If pi Is Nothing Then

            Throw New Exception("Can't find property")

        End If

        Dim collection As IList = DirectCast(pi.GetValue(targetResource, Nothing), IList)

        collection.Remove(resourceToBeRemoved)

    End Sub

 

    ''' <summary>

    ''' Resets the value of the given resource to its default value

    ''' </summary>

    ''' <param name="resource">resource whose value needs to be reset</param>

    ''' <returns>same resource with its value reset</returns>

    Public Function ResetResource(ByVal resource As Object) _

                                  As Object Implements System.Data.Services.IUpdatable.ResetResource

        Dim t As Type = resource.GetType

        Dim table As MetaTable = Mapping.GetTable(t)

        Dim dummyResource As Object = Activator.CreateInstance(t)

        For Each member In table.RowType.DataMembers

 

            If Not member.IsPrimaryKey AndAlso Not member.IsDeferred AndAlso Not member.IsAssociation _

                                       AndAlso Not member.IsDbGenerated Then

                Dim defaultValue As Object = member.MemberAccessor.GetBoxedValue(dummyResource)

                member.MemberAccessor.SetBoxedValue(resource, defaultValue)

            End If

        Next

        Return resource

    End Function

 

    ''' <summary>

    ''' Returns the actual instance of the resource represented by the given resource object

    ''' </summary>

    ''' <param name="resource">object representing the resource whose instance needs to be fetched</param>

    ''' <returns>The actual instance of the resource represented by the given resource object</returns>

    ''' <remarks></remarks>

    Public Function ResolveResource(ByVal resource As Object) _

                                    As Object Implements System.Data.Services.IUpdatable.ResolveResource

        Return resource

    End Function

 

    ''' <summary>

    ''' Saves all the pending changes made till now

    ''' </summary>

    ''' <remarks></remarks>

    Public Sub SaveChanges() Implements System.Data.Services.IUpdatable.SaveChanges

        SubmitChanges()

    End Sub

 

    ''' <summary>

    ''' Sets the value of the given reference property on the target object

    ''' </summary>

    ''' <param name="targetResource">target object which defines the property</param>

    ''' <param name="propertyName">name of the property whose value needs to be updated</param>

    ''' <param name="propertyValue">value of the property</param>

    Public Sub SetReference(ByVal targetResource As Object, ByVal propertyName As String, _

                            ByVal propertyValue As Object) Implements System.Data.Services.IUpdatable.SetReference

        CType(Me, IUpdatable).SetValue(targetResource, propertyName, propertyValue)

    End Sub

 

    ''' <summary>

    ''' Sets the value of the given property on the target object

    ''' </summary>

    ''' <param name="targetResource">target object which defines the property</param>

    ''' <param name="propertyName">name of the property whose value needs to be updated</param>

    ''' <param name="propertyValue">value of the property</param>

    Public Sub SetValue(ByVal targetResource As Object, ByVal propertyName As String, _

                        ByVal propertyValue As Object) Implements System.Data.Services.IUpdatable.SetValue

        Dim table As MetaTable = Mapping.GetTable(targetResource.GetType)

        Dim member As MetaDataMember = table.RowType.DataMembers.Single(Function(x) x.Name = propertyName)

        member.MemberAccessor.SetBoxedValue(targetResource, propertyValue)

    End Sub

End Class

Ora abbiamo tutto ciò che occorre e possiamo utilizzare le medesime tecniche che abbiamo imparato finora, lato client. A puro titolo esemplificativo, il seguente codice ottiene l'elenco degli ordini eseguiti da un certo cliente:

    Sub GetSomeOrders()

 

        Dim query = From ord In NorthwindContext.Orders _

                    Where ord.CustomerID = "ALFKI" _

                    Select ord

 

        For Each ord In query

            Console.WriteLine(ord.OrderID)

        Next

 

        Console.ReadLine()

    End Sub

Mentre il seguente snippet aggiunge un nuovo ordine e lo relaziona a uno specifico cliente:

    Sub AddNewOrder()

 

        Dim ord As New Order

 

        With ord

            .Customer = NorthwindContext.Customers.Where(Function(cust) cust.CustomerID = "ALFKI").First

            .OrderDate = DateTime.Today

            .ShippedDate = DateTime.Today

            .ShipCountry = "Italy"

            .ShipCity = "Cremona"

        End With

 

        NorthwindContext.SetLink(ord, "Customer", ord.Customer)

        NorthwindContext.AddToOrders(ord)

 

        NorthwindContext.SaveChanges()

    End Sub

Le tecniche non cambiano poiché noi andiamo a rapportarci sempre con l'istanza della classe DataService(Of T), che lato client dichiariamo sempre in questo modo:

    Dim NorthwindContext As New NorthwindDataContext(New Uri("http://localhost:4693/NorthwindDataService.svc"))

La versione 1.5 degli ADO.NET Data Services, stando a quanto letto nel blog di Andrew Conrad, dovrebbe includere il supporto per provider diversi da ADO.NET Entity Framework senza implementare manualmente IUpdatable. Nel caso però fosse necessario, è bene sapere come fare.

Nel ringraziare Andrew Conrad per la disponibilità, potete scaricare un file di codice Visual Basic contenente la suesposta implementazione dall'area Download di Visual Basic Tips & Tricks a questo indirizzo.

Alessandro

Print | posted on sabato 25 aprile 2009 21:04 | Filed Under [ Visual Basic LINQ WCF Data Services/WCF RIA Services/OData ]

Powered by:
Powered By Subtext Powered By ASP.NET