Membuat Jenis User-Defined - Pengkodian

Berlaku untuk:SQL Server

Saat mengodekan definisi jenis yang ditentukan pengguna (UDT), Anda harus menerapkan berbagai fitur, tergantung pada apakah Anda menerapkan UDT sebagai kelas atau struktur, serta pada format dan opsi serialisasi yang telah Anda pilih.

Contoh di bagian ini menggambarkan penerapan Point UDT sebagai struct (atau Structure in Visual Basic). Point UDT terdiri dari koordinat X dan Y yang diimplementasikan sebagai prosedur properti.

Namespace berikut diperlukan saat menentukan UDT:

Imports System  
Imports System.Data.SqlTypes  
Imports Microsoft.SqlServer.Server  
using System;  
using System.Data.SqlTypes;  
using Microsoft.SqlServer.Server;  

Namespace Layanan Microsoft.SqlServer.Server berisi objek yang diperlukan untuk berbagai atribut UDT Anda, dan namespace Layanan System.Data.SqlTypes berisi kelas yang mewakili SQL Server jenis data asli yang tersedia untuk perakitan. Mungkin tentu saja ada namespace tambahan yang diperlukan assembly Anda untuk berfungsi dengan benar. Point UDT juga menggunakan namespace System.Text untuk bekerja dengan string.

Catatan

Objek database Visual C++, seperti UDT, yang dikompilasi dengan /clr:pure tidak didukung untuk eksekusi.

Menentukan Atribut

Atribut menentukan bagaimana serialisasi digunakan untuk membangun representasi penyimpanan UDT dan untuk mengirimkan UDT berdasarkan nilai ke klien.

Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute diperlukan. Atribut Serializable bersifat opsional. Anda juga dapat menentukan Microsoft.SqlServer.Server.SqlFacetAttribute untuk memberikan informasi tentang jenis pengembalian UDT. Untuk informasi selengkapnya, lihat Atribut Kustom untuk Rutinitas CLR.

Atribut UDT Titik

Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute mengatur format penyimpanan untuk Point UDT ke Native. IsByteOrdered diatur ke true, yang menjamin bahwa hasil perbandingan sama dalam SQL Server seolah-olah perbandingan yang sama telah terjadi dalam kode terkelola. UDT mengimplementasikan antarmuka System.Data.SqlTypes.INullable untuk membuat UDT sadar null.

Fragmen kode berikut menunjukkan atribut untuk Point UDT.

<Serializable(), SqlUserDefinedTypeAttribute(Format.Native, _  
  IsByteOrdered:=True)> _  
  Public Structure Point  
    Implements INullable  
[Serializable]  
[Microsoft.SqlServer.Server.SqlUserDefinedType(Format.Native,  
  IsByteOrdered=true)]  
public struct Point : INullable  
{  

Menerapkan Nullability

Selain menentukan atribut untuk rakitan Anda dengan benar, UDT Anda juga harus mendukung nullability. UDT yang dimuat ke dalam SQL Server sadar null, tetapi agar UDT mengenali nilai null, UDT harus mengimplementasikan antarmuka System.Data.SqlTypes.INullable.

Anda harus membuat properti bernama IsNull, yang diperlukan untuk menentukan apakah nilai null dari dalam kode CLR. Ketika SQL Server menemukan instans null UDT, UDT tetap menggunakan metode penanganan null normal. Server tidak membuang waktu untuk membuat serialisasi atau deserialisasi UDT jika tidak perlu, dan tidak membuang-buang ruang untuk menyimpan UDT null. Pemeriksaan null ini dilakukan setiap kali UDT dibawa dari CLR, yang berarti bahwa menggunakan konstruksi Transact-SQL IS NULL untuk memeriksa UDT null harus selalu berfungsi. Properti IsNull juga digunakan oleh server untuk menguji apakah instans null. Setelah server menentukan bahwa UDT null, server dapat menggunakan penanganan null aslinya.

Metode get()IsNull tidak dalam kasus khusus dengan cara apa pun. Jika variabel Titik@pnull, maka @p.IsNull akan, secara default, mengevaluasi ke "NULL", bukan "1". Ini karena atribut SqlMethod(OnNullCall) dari metode IsNull get() default ke false. Karena objek adalah Null, ketika properti diminta objek tidak dideserialisasi, metode tidak dipanggil, dan nilai default "NULL" dikembalikan.

Contoh

Dalam contoh berikut, is_Null variabel bersifat privat dan menahan status null untuk instans UDT. Kode Anda harus mempertahankan nilai yang sesuai untuk is_Null. UDT juga harus memiliki properti statis bernama Null yang mengembalikan instans nilai null dari UDT. Ini memungkinkan UDT untuk mengembalikan nilai null jika instans memang null dalam database.

Private is_Null As Boolean  
  
Public ReadOnly Property IsNull() As Boolean _  
   Implements INullable.IsNull  
    Get  
        Return (is_Null)  
    End Get  
End Property  
  
Public Shared ReadOnly Property Null() As Point  
    Get  
        Dim pt As New Point  
        pt.is_Null = True  
        Return (pt)  
    End Get  
End Property  
private bool is_Null;  
  
public bool IsNull  
{  
    get  
    {  
        return (is_Null);  
    }  
}  
  
public static Point Null  
{  
    get  
    {  
        Point pt = new Point();  
        pt.is_Null = true;  
        return pt;  
    }  
}  

IS NULL vs. IsNull

Pertimbangkan tabel yang berisi Titik skema(int id, titik lokasi), di mana Titik adalah UDT CLR, dan kueri berikut:

--Query 1  
SELECT ID  
FROM Points  
WHERE NOT (location IS NULL) -- Or, WHERE location IS NOT NULL;  
--Query 2:  
SELECT ID  
FROM Points  
WHERE location.IsNull = 0;  

Kedua kueri mengembalikan ID titik dengan lokasi non-Null . Di Kueri 1, penanganan null normal digunakan, dan tidak diperlukan deserialisasi UDT. Kueri 2, di sisi lain, harus mendeserialisasi setiap objek non-Null dan memanggil ke CLR untuk mendapatkan nilai properti IsNull . Jelas, menggunakan IS NULL akan menunjukkan performa yang lebih baik dan seharusnya tidak pernah ada alasan untuk membaca properti IsNull dari UDT dari kode Transact-SQL.

Jadi, apa penggunaan properti IsNull ? Pertama, diperlukan untuk menentukan apakah nilai null dari dalam kode CLR. Kedua, server memerlukan cara untuk menguji apakah instans adalah Null, sehingga properti ini digunakan oleh server. Setelah menentukan null, maka dapat menggunakan penanganan null aslinya untuk menanganinya.

Menerapkan Metode Penguraian

Metode Parse dan ToString memungkinkan konversi ke dan dari representasi string UDT. Metode Parse memungkinkan string dikonversi menjadi UDT. Ini harus dinyatakan sebagai statis (atau Dibagikan di Visual Basic), dan mengambil parameter jenis System.Data.SqlTypes.SqlString.

Kode berikut mengimplementasikan metode Parse untuk Point UDT, yang memisahkan koordinat X dan Y. Metode Parse memiliki argumen tunggal dari jenis System.Data.SqlTypes.SqlString, dan mengasumsikan bahwa nilai X dan Y disediakan sebagai string yang dibatasi koma. Mengatur atribut Microsoft.SqlServer.Server.SqlMethodAttribute.OnNullCall ke false mencegah metode Parse dipanggil dari instans Titik null.

<SqlMethod(OnNullCall:=False)> _  
Public Shared Function Parse(ByVal s As SqlString) As Point  
    If s.IsNull Then  
        Return Null  
    End If  
  
    ' Parse input string here to separate out points.  
    Dim pt As New Point()  
    Dim xy() As String = s.Value.Split(",".ToCharArray())  
    pt.X = Int32.Parse(xy(0))  
    pt.Y = Int32.Parse(xy(1))  
    Return pt  
End Function  
[SqlMethod(OnNullCall = false)]  
public static Point Parse(SqlString s)  
{  
    if (s.IsNull)  
        return Null;  
  
    // Parse input string to separate out points.  
    Point pt = new Point();  
    string[] xy = s.Value.Split(",".ToCharArray());  
    pt.X = Int32.Parse(xy[0]);  
    pt.Y = Int32.Parse(xy[1]);  
    return pt;  
}  

Menerapkan Metode ToString

Metode ToString mengonversi Point UDT menjadi nilai string. Dalam hal ini, string "NULL" dikembalikan untuk instans Null dari jenis Titik . Metode ToString membalikkan metode Parse dengan menggunakan System.Text.StringBuilder untuk mengembalikan System.String yang dibatasi koma yang terdiri dari nilai koordinat X dan Y. Karena InvokeIfReceiverIsNull default ke false, pemeriksaan untuk instans null Point tidak perlu.

Private _x As Int32  
Private _y As Int32  
  
Public Overrides Function ToString() As String  
    If Me.IsNull Then  
        Return "NULL"  
    Else  
        Dim builder As StringBuilder = New StringBuilder  
        builder.Append(_x)  
        builder.Append(",")  
        builder.Append(_y)  
        Return builder.ToString  
    End If  
End Function  
private Int32 _x;  
private Int32 _y;  
  
public override string ToString()  
{  
    if (this.IsNull)  
        return "NULL";  
    else  
    {  
        StringBuilder builder = new StringBuilder();  
        builder.Append(_x);  
        builder.Append(",");  
        builder.Append(_y);  
        return builder.ToString();  
    }  
}  

Mengekspos Properti UDT

Point UDT memaparkan koordinat X dan Y yang diimplementasikan sebagai properti baca-tulis publik dari jenis System.Int32.

Public Property X() As Int32  
    Get  
        Return (Me._x)  
    End Get  
  
    Set(ByVal Value As Int32)  
        _x = Value  
    End Set  
End Property  
  
Public Property Y() As Int32  
    Get  
        Return (Me._y)  
    End Get  
  
    Set(ByVal Value As Int32)  
        _y = Value  
    End Set  
End Property  
public Int32 X  
{  
    get  
    {  
        return this._x;  
    }  
    set   
    {  
        _x = value;  
    }  
}  
  
public Int32 Y  
{  
    get  
    {  
        return this._y;  
    }  
    set  
    {  
        _y = value;  
    }  
}  

Memvalidasi Nilai UDT

Saat bekerja dengan data UDT, SQL Server Mesin Database secara otomatis mengonversi nilai biner menjadi nilai UDT. Proses konversi ini melibatkan pemeriksaan bahwa nilai sesuai untuk format serialisasi jenis dan memastikan bahwa nilai dapat dideserialisasi dengan benar. Ini memastikan bahwa nilai dapat dikonversi kembali ke formulir biner. Dalam kasus UDT yang diurutkan byte, ini juga memastikan bahwa nilai biner yang dihasilkan cocok dengan nilai biner asli. Ini mencegah nilai yang tidak valid dipertahankan dalam database. Dalam beberapa kasus, tingkat pemeriksaan ini mungkin tidak memadai. Validasi tambahan mungkin diperlukan ketika nilai UDT diperlukan untuk berada dalam domain atau rentang yang diharapkan. Misalnya, UDT yang mengimplementasikan tanggal mungkin mengharuskan nilai hari menjadi angka positif yang termasuk dalam rentang nilai tertentu yang valid.

Properti Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute.ValidationMethodName dari properti Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute memungkinkan Anda menyediakan nama metode validasi yang dijalankan server saat data ditetapkan ke UDT atau dikonversi ke UDT. ValidationMethodName juga dipanggil selama menjalankan utilitas bcp, BULK INSERT, DBCC CHECKDB, DBCC CHECKFILEGROUP, DBCC CHECKTABLE, kueri terdistribusi, dan operasi panggilan prosedur jarak jauh (RPC) aliran data tabular (TDS). Nilai default untuk ValidationMethodName adalah null, menunjukkan bahwa tidak ada metode validasi.

Contoh

Fragmen kode berikut menunjukkan deklarasi untuk kelas Titik , yang menentukan ValidationMethodName dari ValidatePoint.

<Serializable(), SqlUserDefinedTypeAttribute(Format.Native, _  
  IsByteOrdered:=True, _  
  ValidationMethodName:="ValidatePoint")> _  
  Public Structure Point  
[Serializable]  
[Microsoft.SqlServer.Server.SqlUserDefinedType(Format.Native,  
  IsByteOrdered=true,   
  ValidationMethodName = "ValidatePoint")]  
public struct Point : INullable  
{  

Jika metode validasi ditentukan, metode tersebut harus memiliki tanda tangan yang terlihat seperti fragmen kode berikut.

Private Function ValidationFunction() As Boolean  
    If (validation logic here) Then  
        Return True  
    Else  
        Return False  
    End If  
End Function  
private bool ValidationFunction()  
{  
    if (validation logic here)  
    {  
        return true;  
    }  
    else  
    {  
        return false;  
    }  
}  

Metode validasi dapat memiliki cakupan apa pun dan harus mengembalikan true jika nilainya valid, dan salah jika tidak. Jika metode mengembalikan false atau melempar pengecualian, nilai diperlakukan sebagai tidak valid dan kesalahan dimunculkan.

Dalam contoh di bawah ini, kode hanya memungkinkan nilai nol atau lebih besar koordinat X dan Y.

Private Function ValidatePoint() As Boolean  
    If (_x >= 0) And (_y >= 0) Then  
        Return True  
    Else  
        Return False  
    End If  
End Function  
private bool ValidatePoint()  
{  
    if ((_x >= 0) && (_y >= 0))  
    {  
        return true;  
    }  
    else  
    {  
        return false;  
    }  
}  

Batasan Metode Validasi

Server memanggil metode validasi ketika server melakukan konversi, bukan ketika data dimasukkan dengan mengatur properti individual atau ketika data dimasukkan menggunakan pernyataan TRANSACT-SQL INSERT.

Anda harus secara eksplisit memanggil metode validasi dari setter properti dan metode Uraikan jika Anda ingin metode validasi dijalankan dalam semua situasi. Ini bukan persyaratan, dan dalam beberapa kasus bahkan mungkin tidak diinginkan.

Contoh Validasi Uraian

Untuk memastikan bahwa metode ValidatePoint dipanggil di kelas Titik , Anda harus memanggilnya dari metode Uraikan dan dari prosedur properti yang mengatur nilai koordinat X dan Y. Fragmen kode berikut menunjukkan cara memanggil metode validasi ValidatePoint dari fungsi Uraikan .

<SqlMethod(OnNullCall:=False)> _  
Public Shared Function Parse(ByVal s As SqlString) As Point  
    If s.IsNull Then  
        Return Null  
    End If  
  
    ' Parse input string here to separate out points.  
    Dim pt As New Point()  
    Dim xy() As String = s.Value.Split(",".ToCharArray())  
    pt.X = Int32.Parse(xy(0))  
    pt.Y = Int32.Parse(xy(1))  
  
    ' Call ValidatePoint to enforce validation  
    ' for string conversions.  
    If Not pt.ValidatePoint() Then  
        Throw New ArgumentException("Invalid XY coordinate values.")  
    End If  
    Return pt  
End Function  
[SqlMethod(OnNullCall = false)]  
public static Point Parse(SqlString s)  
{  
    if (s.IsNull)  
        return Null;  
  
    // Parse input string to separate out points.  
    Point pt = new Point();  
    string[] xy = s.Value.Split(",".ToCharArray());  
    pt.X = Int32.Parse(xy[0]);  
    pt.Y = Int32.Parse(xy[1]);  
  
    // Call ValidatePoint to enforce validation  
    // for string conversions.  
    if (!pt.ValidatePoint())   
        throw new ArgumentException("Invalid XY coordinate values.");  
    return pt;  
}  

Contoh Validasi Properti

Fragmen kode berikut menunjukkan cara memanggil metode validasi ValidatePoint dari prosedur properti yang mengatur koordinat X dan Y.

Public Property X() As Int32  
    Get  
        Return (Me._x)  
    End Get  
  
    Set(ByVal Value As Int32)  
        Dim temp As Int32 = _x  
        _x = Value  
        If Not ValidatePoint() Then  
            _x = temp  
            Throw New ArgumentException("Invalid X coordinate value.")  
        End If  
    End Set  
End Property  
  
Public Property Y() As Int32  
    Get  
        Return (Me._y)  
    End Get  
  
    Set(ByVal Value As Int32)  
        Dim temp As Int32 = _y  
        _y = Value  
        If Not ValidatePoint() Then  
            _y = temp  
            Throw New ArgumentException("Invalid Y coordinate value.")  
        End If  
    End Set  
End Property  
    public Int32 X  
{  
    get  
    {  
        return this._x;  
    }  
    // Call ValidatePoint to ensure valid range of Point values.  
    set   
    {  
        Int32 temp = _x;  
        _x = value;  
        if (!ValidatePoint())  
        {  
            _x = temp;  
            throw new ArgumentException("Invalid X coordinate value.");  
        }  
    }  
}  
  
public Int32 Y  
{  
    get  
    {  
        return this._y;  
    }  
    set  
    {  
        Int32 temp = _y;  
        _y = value;  
        if (!ValidatePoint())  
        {  
            _y = temp;  
            throw new ArgumentException("Invalid Y coordinate value.");  
        }  
    }  
}  

Metode UDT Pengodean

Saat mengodekan metode UDT, pertimbangkan apakah algoritma yang digunakan mungkin dapat berubah dari waktu ke waktu. Jika demikian, Anda mungkin ingin mempertimbangkan untuk membuat kelas terpisah untuk metode yang digunakan UDT Anda. Jika algoritma berubah, Anda dapat mengkompilasi ulang kelas dengan kode baru dan memuat rakitan ke dalam SQL Server tanpa memengaruhi UDT. Dalam banyak kasus, UDT dapat dimuat ulang menggunakan pernyataan TRANSACT-SQL ALTER ASSEMBLY, tetapi itu berpotensi menyebabkan masalah dengan data yang ada. Misalnya, UDT Mata Uang yang disertakan dengan database sampel AdventureWorks menggunakan fungsi ConvertCurrency untuk mengonversi nilai mata uang, yang diimplementasikan di kelas terpisah. Ada kemungkinan bahwa algoritma konversi dapat berubah dengan cara yang tidak dapat diprediksi di masa depan, atau bahwa fungsionalitas baru mungkin diperlukan. Memisahkan fungsi ConvertCurrency dari implementasi UDT Mata Uang memberikan fleksibilitas yang lebih besar saat merencanakan perubahan di masa mendatang.

Contoh

Kelas Titik berisi tiga metode sederhana untuk menghitung jarak: Jarak, JarakDari dan DistanceFromXY. Setiap mengembalikan ganda yang menghitung jarak dari Titik ke nol, jarak dari titik ke Titik tertentu, dan jarak dari koordinat X dan Y yang ditentukan ke Titik. Jarak dan JarakDari setiap panggilan DistanceFromXY, dan menunjukkan cara menggunakan argumen yang berbeda untuk setiap metode.

' Distance from 0 to Point.  
<SqlMethod(OnNullCall:=False)> _  
Public Function Distance() As Double  
    Return DistanceFromXY(0, 0)  
End Function  
  
' Distance from Point to the specified point.  
<SqlMethod(OnNullCall:=False)> _  
Public Function DistanceFrom(ByVal pFrom As Point) As Double  
    Return DistanceFromXY(pFrom.X, pFrom.Y)  
End Function  
  
' Distance from Point to the specified x and y values.  
<SqlMethod(OnNullCall:=False)> _  
Public Function DistanceFromXY(ByVal ix As Int32, ByVal iy As Int32) _  
    As Double  
    Return Math.Sqrt(Math.Pow(ix - _x, 2.0) + Math.Pow(iy - _y, 2.0))  
End Function  
// Distance from 0 to Point.  
[SqlMethod(OnNullCall = false)]  
public Double Distance()  
{  
    return DistanceFromXY(0, 0);  
}  
  
// Distance from Point to the specified point.  
[SqlMethod(OnNullCall = false)]  
public Double DistanceFrom(Point pFrom)  
{  
    return DistanceFromXY(pFrom.X, pFrom.Y);  
}  
  
// Distance from Point to the specified x and y values.  
[SqlMethod(OnNullCall = false)]  
public Double DistanceFromXY(Int32 iX, Int32 iY)  
{  
    return Math.Sqrt(Math.Pow(iX - _x, 2.0) + Math.Pow(iY - _y, 2.0));  
}  

Menggunakan Atribut SqlMethod

Kelas Microsoft.SqlServer.Server.SqlMethodAttribute menyediakan atribut kustom yang dapat digunakan untuk menandai definisi metode untuk menentukan determinisme, pada perilaku panggilan null, dan untuk menentukan apakah metode adalah mutator. Nilai default untuk properti ini diasumsikan, dan atribut kustom hanya digunakan saat nilai non-default diperlukan.

Catatan

Kelas SqlMethodAttribute mewarisi dari kelas SqlFunctionAttribute , sehingga SqlMethodAttribute mewarisi bidang FillRowMethodName dan TableDefinition dari SqlFunctionAttribute. Ini menyiratkan bahwa dimungkinkan untuk menulis metode bernilai tabel, yang tidak terjadi. Metode ini mengkompilasi dan rakitan disebarkan, tetapi kesalahan tentang jenis pengembalian IEnumerable dinaikkan pada runtime dengan pesan berikut: "Metode, properti, atau bidang '<nama>' di kelas '<kelas>' di rakitan '<rakitan>' memiliki jenis pengembalian yang tidak valid."

Tabel berikut ini menjelaskan beberapa properti Microsoft.SqlServer.Server.SqlMethodAttribute yang relevan yang dapat digunakan dalam metode UDT, dan mencantumkan nilai defaultnya.

DataAccess
Menunjukkan apakah fungsi melibatkan akses ke data pengguna yang disimpan dalam instans lokal SQL Server. Defaultnya adalah DataAccessKind. Tidak ada.

IsDeterministic
Menunjukkan apakah fungsi menghasilkan nilai output yang sama dengan nilai input yang sama dan status database yang sama. Default adalah salah.

IsMutator
Menunjukkan apakah metode menyebabkan perubahan status dalam instans UDT. Default adalah salah.

IsPrecise
Menunjukkan apakah fungsi melibatkan komputasi yang tidak tepat, seperti operasi floating point. Default adalah salah.

OnNullCall
Menunjukkan apakah metode dipanggil ketika argumen input referensi null ditentukan. Default-nya adalah true.

Contoh

Properti Microsoft.SqlServer.Server.SqlMethodAttribute.IsMutator memungkinkan Anda menandai metode yang memungkinkan perubahan status instans UDT. Transact-SQL tidak memungkinkan Anda mengatur dua properti UDT dalam klausa SET dari satu pernyataan UPDATE. Namun, Anda dapat memiliki metode yang ditandai sebagai mutator yang mengubah kedua anggota.

Catatan

Metode mutator tidak diperbolehkan dalam kueri. Mereka hanya dapat dipanggil dalam pernyataan penugasan atau pernyataan modifikasi data. Jika metode yang ditandai sebagai mutator tidak mengembalikan kekosongan (atau bukan Sub di Visual Basic), CREATE TYPE gagal dengan kesalahan.

Pernyataan berikut mengasumsikan keberadaan UDT Segitiga yang memiliki metode Putar . Pernyataan pembaruan Transact-SQL berikut memanggil metode Putar :

UPDATE Triangles SET t.RotateY(0.6) WHERE id=5  

Metode Putar dihiasi dengan pengaturan atribut SqlMethodIsMutator ke true sehingga SQL Server dapat menandai metode sebagai metode mutator. Kode ini juga mengatur OnNullCall ke false, yang menunjukkan ke server bahwa metode mengembalikan referensi null (Tidak ada di Visual Basic) jika salah satu parameter input adalah referensi null.

<SqlMethod(IsMutator:=True, OnNullCall:=False)> _  
Public Sub Rotate(ByVal anglex as Double, _  
  ByVal angley as Double, ByVal anglez As Double)   
   RotateX(anglex)  
   RotateY(angley)  
   RotateZ(anglez)  
End Sub  
[SqlMethod(IsMutator = true, OnNullCall = false)]  
public void Rotate(double anglex, double angley, double anglez)   
{  
   RotateX(anglex);  
   RotateY(angley);  
   RotateZ(anglez);  
}  

Menerapkan UDT dengan Format User-Defined

Saat menerapkan UDT dengan format yang ditentukan pengguna, Anda harus menerapkan metode Baca dan Tulis yang mengimplementasikan antarmuka Microsoft.SqlServer.Server.IBinarySerialize untuk menangani serialisasi dan deserialisasi data UDT. Anda juga harus menentukan properti MaxByteSize dari Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute.

Mata Uang UDT

UDT Mata Uang disertakan dengan sampel CLR yang dapat diinstal dengan SQL Server, dimulai dengan SQL Server 2005 (9,x).

UDT Mata Uang mendukung penanganan jumlah uang dalam sistem moneter budaya tertentu. Anda harus menentukan dua bidang: string untuk CultureInfo, yang menentukan siapa yang mengeluarkan mata uang (misalnya, en-us) dan desimal untuk CurrencyValue, jumlah uang.

Meskipun tidak digunakan oleh server untuk melakukan perbandingan, UDT Mata Uang mengimplementasikan antarmuka System.IComparable , yang mengekspos satu metode, System.IComparable.CompareTo. Ini digunakan di sisi klien dalam situasi di mana diinginkan untuk secara akurat membandingkan atau memesan nilai mata uang dalam budaya.

Kode yang berjalan di CLR membandingkan budaya secara terpisah dari nilai mata uang. Untuk kode T-SQL, tindakan berikut menentukan perbandingan:

  1. Atur atribut IsByteOrdered ke true, yang memberi tahu SQL Server untuk menggunakan representasi biner yang bertahan pada disk untuk perbandingan.

  2. Gunakan metode Tulis untuk UDT Mata Uang untuk menentukan bagaimana UDT bertahan pada disk dan oleh karena itu bagaimana nilai UDT dibandingkan dan diurutkan untuk operasi Transact-SQL.

  3. Simpan UDT Mata Uang menggunakan format biner berikut:

    1. Simpan budaya sebagai string yang dikodekan UTF-16 untuk byte 0-19 dengan padding di sebelah kanan dengan karakter null.

    2. Gunakan byte 20 ke atas untuk berisi nilai desimal mata uang.

Tujuan dari padding adalah untuk memastikan bahwa budaya benar-benar terpisah dari nilai mata uang, sehingga ketika satu UDT dibandingkan dengan yang lain dalam kode Transact-SQL, byte budaya dibandingkan dengan byte budaya, dan nilai byte mata uang dibandingkan dengan nilai byte mata uang.

Atribut Mata Uang

UDT Mata Uang didefinisikan dengan atribut berikut.

<Serializable(), Microsoft.SqlServer.Server.SqlUserDefinedType( _  
    Microsoft.SqlServer.Server.Format.UserDefined, _  
    IsByteOrdered:=True, MaxByteSize:=32), _  
    CLSCompliant(False)> _  
Public Structure Currency  
Implements INullable, IComparable, _  
Microsoft.SqlServer.Server.IBinarySerialize  
[Serializable]  
[SqlUserDefinedType(Format.UserDefined,   
    IsByteOrdered = true, MaxByteSize = 32)]  
    [CLSCompliant(false)]  
    public struct Currency : INullable, IComparable, IBinarySerialize  
    {  

Membuat Metode Baca dan Tulis dengan IBinarySerialize

Saat Anda memilih format serialisasi UserDefined , Anda juga harus mengimplementasikan antarmuka IBinarySerialize dan membuat metode Baca dan Tulis Anda sendiri. Prosedur berikut dari UDT Mata Uang menggunakan System.IO.BinaryReader dan System.IO.BinaryWriter untuk membaca dari dan menulis ke UDT.

' IBinarySerialize methods  
' The binary layout is as follow:  
'    Bytes 0 - 19: Culture name, padded to the right with null  
'    characters, UTF-16 encoded  
'    Bytes 20+: Decimal value of money  
' If the culture name is empty, the currency is null.  
Public Sub Write(ByVal w As System.IO.BinaryWriter) _  
  Implements Microsoft.SqlServer.Server.IBinarySerialize.Write  
    If Me.IsNull Then  
        w.Write(nullMarker)  
        w.Write(System.Convert.ToDecimal(0))  
        Return  
    End If  
  
    If cultureName.Length > cultureNameMaxSize Then  
        Throw New ApplicationException(String.Format(CultureInfo.CurrentUICulture, _  
           "{0} is an invalid culture name for currency as it is too long.", cultureNameMaxSize))  
    End If  
  
    Dim paddedName As String = cultureName.PadRight(cultureNameMaxSize, CChar(vbNullChar))  
  
    For i As Integer = 0 To cultureNameMaxSize - 1  
        w.Write(paddedName(i))  
    Next i  
  
    ' Normalize decimal value to two places  
    currencyVal = Decimal.Floor(currencyVal * 100) / 100  
    w.Write(currencyVal)  
End Sub  
  
Public Sub Read(ByVal r As System.IO.BinaryReader) _  
  Implements Microsoft.SqlServer.Server.IBinarySerialize.Read  
    Dim name As Char() = r.ReadChars(cultureNameMaxSize)  
    Dim stringEnd As Integer = Array.IndexOf(name, CChar(vbNullChar))  
  
    If stringEnd = 0 Then  
        cultureName = Nothing  
        Return  
    End If  
  
    cultureName = New String(name, 0, stringEnd)  
    currencyVal = r.ReadDecimal()  
End Sub  
  
// IBinarySerialize methods  
// The binary layout is as follow:  
//    Bytes 0 - 19:Culture name, padded to the right   
//    with null characters, UTF-16 encoded  
//    Bytes 20+:Decimal value of money  
// If the culture name is empty, the currency is null.  
public void Write(System.IO.BinaryWriter w)  
{  
    if (this.IsNull)  
    {  
        w.Write(nullMarker);  
        w.Write((decimal)0);  
        return;  
    }  
  
    if (cultureName.Length > cultureNameMaxSize)  
    {  
        throw new ApplicationException(string.Format(  
            CultureInfo.InvariantCulture,   
            "{0} is an invalid culture name for currency as it is too long.",   
            cultureNameMaxSize));  
    }  
  
    String paddedName = cultureName.PadRight(cultureNameMaxSize, '\0');  
    for (int i = 0; i < cultureNameMaxSize; i++)  
    {  
        w.Write(paddedName[i]);  
    }  
  
    // Normalize decimal value to two places  
    currencyValue = Decimal.Floor(currencyValue * 100) / 100;  
    w.Write(currencyValue);  
}  
public void Read(System.IO.BinaryReader r)  
{  
    char[] name = r.ReadChars(cultureNameMaxSize);  
    int stringEnd = Array.IndexOf(name, '\0');  
  
    if (stringEnd == 0)  
    {  
        cultureName = null;  
        return;  
    }  
  
    cultureName = new String(name, 0, stringEnd);  
    currencyValue = r.ReadDecimal();  
}  

Lihat juga

Membuat Jenis User-Defined