Requisiti per i tipi definiti dall'utente
Quando si crea un tipo definito dall'utente da installare in MicrosoftSQL Server, è necessario adottare alcune importanti decisioni di progettazione. Benché nella maggior parte dei casi sia consigliabile creare il tipo definito dall'utente come struttura, la creazione come classe rappresenta un'altra opzione valida. Perché il tipo venga registrato con SQL Server, la definizione del tipo definito dall'utente deve essere conforme alle specifiche relative alla creazione di tali tipi.
Requisiti per l'implementazione di tipi definiti dall'utente
Ai fini dell'esecuzione in SQL Server, il tipo definito dall'utente deve implementare i requisiti seguenti nella relativa definizione:
Il tipo definito dall'utente deve specificare Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute. L'utilizzo di System.SerializableAttribute è facoltativo ma consigliato.
Il tipo definito dall'utente deve implementare l'interfaccia System.Data.SqlTypes.INullable nella classe o nella struttura creando un metodo Nullstatic (Shared in Microsoft Visual Basic) pubblico. SQL Server supporta i valori Null per impostazione predefinita. Questa condizione è necessaria affinché il codice in esecuzione nel tipo definito dall'utente sia in grado di riconoscere un valore Null.
Il tipo definito dall'utente deve contenere un metodo Parsestatic (o Shared) che supporti l'analisi e un metodo ToString pubblico per la conversione in una rappresentazione di stringa dell'oggetto.
Un tipo definito dall'utente con un formato di serializzazione definito dall'utente deve implementare l'interfaccia System.Data.IBinarySerialize e fornire un metodo Read e un metodo Write.
Il tipo definito dall'utente deve implementare System.Xml.Serialization.IXmlSerializable. In caso contrario, tutti i campi e le proprietà pubblici devono essere di tipi compatibili con la serializzazione XML o decorati con l'attributo XmlIgnore se è necessario sostituire la serializzazione standard.
È necessario che sia presente solo una serializzazione di un oggetto del tipo definito dall'utente. La convalida ha esito negativo se le routine di serializzazione e deserializzazione riconoscono più di una rappresentazione di un oggetto specifico.
SqlUserDefinedTypeAttribute.IsByteOrdered deve essere true per confrontare i dati ordinati per byte. Se l'interfaccia IComparable non viene implementata e SqlUserDefinedTypeAttribute.IsByteOrdered è false, i confronti ordinati per byte non riusciranno.
Un tipo definito dall'utente specificato in una classe deve includere un costruttore pubblico che non accetta argomenti. È eventualmente possibile creare costruttori di classe di overload aggiuntivi.
Il tipo definito dall'utente deve esporre elementi dati come campi pubblici o routine di proprietà.
I nomi pubblici non possono essere più lunghi di 128 caratteri e devono essere conformi alle regole di denominazione di SQL Server per gli identificatori, in base a quanto definito in Identificatori.
Le colonne sql_variant non possono contenere istanze di un tipo definito dall'utente.
I membri ereditati non sono accessibili da Transact-SQL perché il sistema dei tipi di SQL Server non riconosce la gerarchia di ereditarietà tra tipi definiti dall'utente. È tuttavia possibile utilizzare l'ereditarietà quando si strutturano le classi ed è possibile chiamare tali metodi nell'implementazione di codice gestito del tipo.
Non è possibile eseguire l'overload dei membri, ad eccezione del costruttore della classe. Se si crea un metodo di overload, non viene generato alcun errore quando si registra l'assembly o si crea il tipo in SQL Server. Il rilevamento del metodo di overload si verifica in fase di esecuzione e non durante la creazione del tipo. Nella classe possono essere presenti metodi di overload, a condizione che non vengano mai richiamati. Quando si richiama il metodo di overload, viene generato un errore.
Qualsiasi membro static (o Shared) deve essere dichiarato come costante o come di sola lettura. I membri statici non possono essere modificati.
A partire da SQL Server 2008, se il campo SqlUserDefinedTypeAttribute.MaxByteSize è impostato su -1, le dimensioni del tipo definito dall'utente serializzato possono raggiungere il limite di dimensioni per gli oggetti LOB (attualmente 2 GB). Le dimensioni del tipo definito dall'utente non possono superare il valore specificato nel campo MaxByteSized.
[!NOTA]
Benché non venga utilizzata dal server per l'esecuzione di confronti, è eventualmente possibile implementare l'interfaccia System.IComparable, che espone un singolo metodo, ovvero CompareTo. Tale metodo viene utilizzato sul lato client in situazioni in cui è preferibile confrontare o ordinare in modo accurato i valori del tipo definito dall'utente.
Serializzazione nativa
La scelta degli attributi di serializzazione corretti per il tipo definito dall'utente dipende dal tipo definito dall'utente che si desidera creare. Il formato di serializzazione Native utilizza una struttura molto semplice che consente di archiviare in SQL Server una rappresentazione nativa efficace del tipo definito dall'utente nel disco. Il formato Native rappresenta la scelta consigliata se il tipo definito dall'utente è semplice e contiene solo campi dei tipi seguenti:
bool, byte, sbyte, short, ushort, int, uint, long, ulong, float, double, SqlByte, SqlInt16, SqlInt32, SqlInt64, SqlDateTime, SqlSingle, SqlDouble, SqlMoney, SqlBoolean
I tipi di valore composti da campi che utilizzano i tipi elencati in precedenza costituiscono candidati validi per il formato Native, ad esempio structs in Visual C# (o Structures, come viene denominato in Visual Basic). Un tipo definito dall'utente specificato, ad esempio, con il formato di serializzazione Native può contenere un campo di un altro tipo definito dall'utente specificato anch'esso con il formato Native. Se la definizione del tipo definito dall'utente è più complessa e contiene tipi di dati non inclusi nell'elenco precedente, è invece necessario specificare il formato di serializzazione UserDefined.
Il formato Native deve soddisfare i requisiti seguenti:
Il tipo non deve specificare un valore per Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute.MaxByteSize.
Tutti i campi devono essere serializzabili.
System.Runtime.InteropServices.StructLayoutAttribute deve essere specificato come StructLayout.LayoutKindSequential se il tipo definito dall'utente è specificato in una classe e non in una struttura. Questo attributo controlla il layout fisico dei campi dati e viene utilizzato per forzare la disposizione dei membri in base all'ordine in cui vengono visualizzati. SQL Server utilizza questo attributo per determinare l'ordine dei campi per i tipi definiti dall'utente con più valori.
Per un esempio di un tipo definito dall'utente specificato con serializzazione Native, vedere il tipo definito dall'utente Point in Codifica dei tipi definiti dall'utente.
Serializzazione UserDefined
L'impostazione del formato UserDefined per l'attributo Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute garantisce allo sviluppatore il controllo completo sul formato binario. Quando si specifica la proprietà dell'attributo Format come UserDefined, è necessario effettuare le operazioni seguenti nel codice:
Specificare la proprietà dell'attributo IsByteOrdered facoltativa. Il valore predefinito è false.
Specificare la proprietà MaxByteSize di Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute.
Scrivere il codice per implementare i metodi Read e Write per il tipo definito dall'utente implementando l'interfaccia System.Data.Sql.IBinarySerialize.
Per un esempio di un tipo definito dall'utente con serializzazione UserDefined, vedere il tipo definito dall'utente Currency in Codifica dei tipi definiti dall'utente.
[!NOTA]
A partire da SQL Server 2005 versione RTM, i tipi CLR definiti dall'utente con serializzazione definita dall'utente possono disporre di campi propri indicizzati come parte di colonne o viste calcolate non persistenti. Poiché in tali situazioni la serializzazione o la deserializzazione dei tipi definiti dall'utente non deterministici può danneggiare l'indice, è stata rimossa da SQL Server 2005 SP1. Ai fini dell'indicizzazione, in SQL Server 2005 SP1 i campi con tipo definito dall'utente devono utilizzare la serializzazione nativa o essere resi persistenti. Tutti gli indici esistenti nei campi con tipo definito dall'utente continueranno a funzionare come nelle versioni precedenti.
Attributi di serializzazione
Gli attributi determinano la modalità di utilizzo della serializzazione per costruire la rappresentazione di archiviazione dei tipi definiti dall'utente e per trasmettere tali tipi al client in base al valore. Quando si crea il tipo definito dall'utente, viene richiesto di specificare Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute. L'attributo Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute indica che la classe è un tipo definito dall'utente e specifica l'archiviazione per il tipo definito dall'utente. È eventualmente possibile specificare l'attributo Serializable, anche se non è necessario in SQL Server.
Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute include le proprietà indicate di seguito.
Format
Specifica il formato di serializzazione, che può essere Native o UserDefined a seconda dei tipi di dati del tipo definito dall'utente.IsByteOrdered
Valore Boolean che determina la modalità di esecuzione dei confronti binari nel tipo definito dall'utente in SQL Server.IsFixedLength
Indica se tutte le istanze del tipo definito dall'utente sono della stessa lunghezza.MaxByteSize
Dimensioni massime, in byte, dell'istanza. È necessario specificare MaxByteSize con il formato di serializzazione UserDefined. Per un tipo definito dall'utente per cui è specificata una serializzazione definita dall'utente, MaxByteSize si riferisce alle dimensioni totali del tipo definito dall'utente nel formato serializzato definito dall'utente. Il valore di MaxByteSize deve essere compreso nell'intervallo tra 1 e 8000 o impostato su -1 a indicare che il tipo definito dall'utente è maggiore di 8000 byte (le dimensioni totali non possono superare le dimensioni LOB massime). Si consideri un tipo definito dall'utente con una proprietà di una stringa di 10 caratteri (System.Char). Quando il tipo definito dall'utente viene serializzato utilizzando un oggetto BinaryWriter, le dimensioni totali della stringa serializzata sono pari a 22 byte per ciascun carattere Unicode UTF-16, moltiplicati per il numero massimo di caratteri, più 2 byte di controllo per l'overhead generato dalla serializzazione di un flusso binario. Di conseguenza, nel determinare il valore di MaxByteSize, è necessario considerare le dimensioni totali del tipo definito dall'utente serializzato, ovvero le dimensioni dei dati serializzati in formato binario più l'overhead generato dalla serializzazione.ValidationMethodName
Nome del metodo utilizzato per convalidare le istanze del tipo definito dall'utente.
Impostazione di IsByteOrdered
Impostando la proprietà Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute.IsByteOrdered su true, si garantisce che i dati binari serializzati possono essere utilizzati per l'ordinamento semantico delle informazioni. In questo modo, ogni istanza di un oggetto del tipo definito dall'utente ordinato per byte può disporre di una sola rappresentazione serializzata. Se in SQL Server viene eseguita un'operazione di confronto sui byte serializzati, i risultati di tale operazione dovranno essere identici a quelli di un caso in cui la stessa operazione di confronto venga eseguita nel codice gestito. Se la proprietà IsByteOrdered è impostata su true, sono supportate le funzionalità seguenti:
Capacità di creare indici nelle colonne di questo tipo.
Capacità di creare chiavi primarie ed esterne, nonché vincoli CHECK e UNIQUE sulle colonne di questo tipo.
Capacità di utilizzare le clausole Transact-SQL ORDER BY, GROUP BY e PARTITION BY. In questi casi, per determinare l'ordine viene utilizzata la rappresentazione binaria del tipo.
Capacità di utilizzare operatori di confronto in istruzioni Transact-SQL.
Capacità di garantire la persistenza delle colonne calcolate di questo tipo.
Si noti che i formati di serializzazione Native e UserDefined supportano gli operatori di confronto seguenti quando IsByteOrdered è impostato su true.
Uguale a (=)
Diverso da (!=)
Maggiore di (>)
Minore di (<)
Maggiore o uguale a (>=)
Minore o uguale a (<=)
Implementazione del supporto di valori Null
Oltre a specificare correttamente gli attributi per gli assembly, la classe deve inoltre supportare i valori Null. Benché i tipi definiti dall'utente caricati in SQL Server supportino i valori Null, perché un tipo definito dall'utente possa riconoscere un valore Null è necessario che la classe implementi l'interfaccia INullable. Per ulteriori informazioni e per visualizzare un esempio dell'implementazione del supporto di valori Null in un tipo definito dall'utente, vedere Codifica dei tipi definiti dall'utente.
Conversioni di stringhe
Per supportare la conversione di stringhe da e verso il tipo definito dall'utente, è necessario fornire un metodo Parse e un metodo ToString nella classe. Il metodo Parse consente la conversione di una stringa in un tipo definito dall'utente. Tale metodo deve essere dichiarato come static (o Shared in Visual Basic) e accetta un parametro di tipo System.Data.SqlTypes.SqlString. Per ulteriori informazioni e per visualizzare un esempio dell'implementazione dei metodi Parse e ToString, vedere Codifica dei tipi definiti dall'utente.
Serializzazione XML
I tipi definiti dall'utente devono supportare la conversione da e verso il tipo di dati xml rispettando la conformità al contratto per la serializzazione XML. Nello spazio dei nomi System.Xml.Serialization sono contenute classi utilizzate per la serializzazione di oggetti in documenti o flussi di formato XML. È possibile scegliere di implementare la serializzazione xml utilizzando l'interfaccia IXmlSerializable, che fornisce formattazione personalizzata per la serializzazione e la deserializzazione XML.
Oltre a eseguire conversioni esplicite dal tipo definito dall'utente a xml, la serializzazione XML consente di effettuare le operazioni seguenti:
Utilizzare Xquery su valori di istanze del tipo definito dall'utente dopo la conversione al tipo di dati xml.
Utilizzare i tipi definiti dall'utente in metodi Web e query con parametri con i servizi Web XML nativi in SQL Server. Per ulteriori informazioni, vedere Gestione del tipo di dati xml e dei tipi CLR definiti dall'utente.
Utilizzare i tipi definiti dall'utente per ricevere un caricamento bulk di dati XML.
Serializzare set di dati che contengono tabelle con colonne del tipo definito dall'utente.
I tipi definiti dall'utente non vengono serializzati nelle query FOR XML. Per eseguire una query FOR XML che visualizza la serializzazione XML dei tipi definiti dall'utente, convertire in modo esplicito ogni colonna del tipo definito dall'utente nel tipo di dati xml nell'istruzione SELECT. È inoltre possibile convertire esplicitamente le colonne in varbinary, varchar o nvarchar.