Erstellen benutzerdefinierter Typen: Codieren

Gilt für:SQL Server

Wenn Sie die Definition eines benutzerdefinierten Typs (UDT) schreiben, müssen Sie verschiedene Funktionen implementieren, abhängig davon, ob Sie den UDT als Klasse oder als Struktur implementieren, sowie abhängig von den von Ihnen gewählten Format- und Serialisierungsoptionen.

Das Beispiel in diesem Abschnitt veranschaulicht die Implementierung einer Punkt-UDT als Struktur (oder Struktur in Visual Basic). Die Punkt-UDT besteht aus X- und Y-Koordinaten, die als Eigenschaftenprozeduren implementiert werden.

Beim Definieren eines UDTs sind die folgenden Namespaces erforderlich:

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

Der Microsoft.SqlServer.Server-Namespace enthält die Objekte, die für verschiedene Attribute Ihrer UDT erforderlich sind, und der System.Data.SqlTypes-Namespace enthält die Klassen, die SQL Server nativen Datentypen darstellen, die für die Assembly verfügbar sind. Es kann natürlich zusätzliche Namespaces geben, die eine Assembly erfordert, um ordnungsgemäß zu funktionieren. Point UDT verwendet auch den System.Text-Namespace für die Arbeit mit Zeichenfolgen.

Hinweis

Visual C++-Datenbankobjekte, z. B. UDTs, die mit /clr:pure kompiliert wurden, werden für die Ausführung nicht unterstützt.

Angeben von Attributen

Attribute bestimmen, wie die Serialisierung verwendet wird, um die Speicherdarstellung von UDTs zu erstellen und um UDTs durch Werte an den Client zu übertragen.

Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute ist erforderlich. Das Serializable-Attribut ist optional. Sie können auch microsoft.SqlServer.Server.SqlFacetAttribute angeben, um Informationen zum Rückgabetyp eines UDT bereitzustellen. Weitere Informationen finden Sie unter Benutzerdefinierte Attribute für CLR-Routinen.

Attribute des Point-UDT

Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute legt das Speicherformat für point UDT auf Native fest. IsByteOrdered ist auf true festgelegt, was garantiert, dass die Vergleichsergebnisse in SQL Server identisch sind, als ob derselbe Vergleich in verwaltetem Code stattgefunden hätte. Die UDT implementiert die System.Data.SqlTypes.INullable-Schnittstelle , um den UDT null-Wert zu erkennen.

Das folgende Codefragment zeigt die Attribute für die Punkt-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  
{  

Implementieren von NULL-Zulässigkeit

Zusätzlich zum ordnungsgemäßen Angeben der Attribute für die Assemblys muss der UDT auch die NULL-Zulässigkeit unterstützen. UdTs, die in SQL Server geladen werden, sind NULL-fähig. Damit die UDT jedoch einen NULL-Wert erkennt, muss die UDT die System.Data.SqlTypes.INullable-Schnittstelle implementieren.

Sie müssen eine Eigenschaft mit dem Namen IsNull erstellen, die erforderlich ist, um zu bestimmen, ob ein Wert null ist, innerhalb des CLR-Codes. Wenn SQL Server einen NULL-instance eines UDT findet, wird der UDT mit normalen NULL-Behandlungsmethoden beibehalten. Der Server vergeudet keine Zeit mit dem Serialisieren oder Deserialisieren des UDTs, wenn dies nicht erforderlich ist, und er verschwendet keinen Platz zum Speichern des NULL-UDTs. Diese Überprüfung auf NULLs wird jedes Mal durchgeführt, wenn ein UDT von der CLR übernommen wird. Dies bedeutet, dass die Verwendung des Transact-SQL IS NULL-Konstrukts zur Überprüfung auf NULL-UDTs immer funktionieren sollte. Die IsNull-Eigenschaft wird auch vom Server verwendet, um zu testen, ob ein instance NULL ist. Sobald der Server bestimmt, dass der UDT NULL ist, kann er seine systemeigene NULL-Behandlung verwenden.

Die get() -Methode von IsNull ist in keiner Weise sonderrechtlich. Wenn eine Point-Variable@pNULL ist, wird @p.IsNull standardmäßig auf "NULL" und nicht auf "1" ausgewertet. Dies liegt daran, dass das SqlMethod(OnNullCall) -Attribut der IsNull get() -Methode standardmäßig auf false lautet. Da das Objekt NULL ist, wird das Objekt beim Anfordern der -Eigenschaft nicht deserialisiert, die -Methode wird nicht aufgerufen, und der Standardwert "NULL" wird zurückgegeben.

Beispiel

Im folgenden Beispiel ist die is_Null-Variable privat und enthält für die Instanz des UDT den Status NULL. Im Code muss ein entsprechender Wert für is_Null verwaltet werden. Die UDT muss auch über eine statische Eigenschaft namens Null verfügen, die einen NULL-Wert instance des UDT zurückgibt. Dadurch kann der UDT einen NULL-Wert zurückgeben, wenn die Instanz auch in der Datenbank tatsächlich NULL ist.

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 und IsNull

Betrachten Sie eine Tabelle, die das Schema Points(id int, location Point), wobei Point ein CLR-UDT ist, und die folgenden Abfragen enthält:

--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;  

Beide Abfragen geben die IDs von Punkten mit Nicht-NULL-Speicherorten zurück. In Abfrage 1 wird die normale NULL-Behandlung verwendet, und dort ist keine Deserialisierung von UDTs erforderlich. Abfrage 2 hingegen muss jedes Nicht-Null-Objekt deserialisieren und die CLR aufrufen, um den Wert der IsNull-Eigenschaft abzurufen. Es ist klar, dass die Verwendung von IS NULL eine bessere Leistung aufweist, und es sollte nie einen Grund geben, die IsNull-Eigenschaft eines UDT aus Transact-SQL-Code zu lesen.

Was ist also die Verwendung der IsNull-Eigenschaft ? Zunächst muss ermittelt werden, ob ein Wert aus CLR-Code NULL ist. Zweitens benötigt der Server eine Möglichkeit, zu testen, ob ein instance NULL ist, sodass diese Eigenschaft vom Server verwendet wird. Nachdem es festgestellt hat, dass es NULL ist, kann es seine native NULL-Behandlung verwenden, um sie zu behandeln.

Implementieren der Parse-Methode

Die Methoden Parse und ToString ermöglichen Konvertierungen in und aus Zeichenfolgendarstellungen des UDT. Mit der Parse-Methode kann eine Zeichenfolge in eine UDT konvertiert werden. Sie muss als statisch (oder in Visual Basic freigegeben ) deklariert werden und einen Parameter vom Typ System.Data.SqlTypes.SqlString verwenden.

Der folgende Code implementiert die Analysemethode für die Point-UDT , die die X- und Y-Koordinaten trennt. Die Parse-Methode verfügt über ein einzelnes Argument vom Typ System.Data.SqlTypes.SqlString und geht davon aus, dass X- und Y-Werte als durch Trennzeichen getrennte Zeichenfolge angegeben werden. Wenn Sie das Microsoft.SqlServer.Server.SqlMethodAttribute.OnNullCall-Attribut auf false festlegen, wird verhindert, dass die Parse-Methode von null instance von Point aufgerufen wird.

<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;  
}  

Implementieren der ToString-Methode

Die ToString-Methode konvertiert den Punkt-UDT in einen Zeichenfolgenwert. In diesem Fall wird die Zeichenfolge "NULL" für einen Null-instance des Point-Typs zurückgegeben. Die ToString-Methode kehrt die Parse-Methode um, indem sie einen System.Text.StringBuilder verwendet, um ein durch Trennzeichen getrenntes System.String zurückzugeben, das aus den X- und Y-Koordinatenwerten besteht. Da InvokeIfReceiverIsNull standardmäßig auf false festgelegt ist, ist die Überprüfung auf eine NULL-instance von Point nicht erforderlich.

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();  
    }  
}  

Bereitstellen der UDT-Eigenschaften

Die Punkt-UDT macht X- und Y-Koordinaten verfügbar, die als öffentliche Lese-/Schreibeigenschaften vom Typ System.Int32 implementiert sind.

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;  
    }  
}  

Überprüfen von UDT-Werten

Bei der Arbeit mit UDT-Daten konvertiert SQL Server Datenbank-Engine binärwerte automatisch in UDT-Werte. Im Rahmen dieses Konvertierungsprozesses muss überprüft werden, ob sich die Werte für das Serialisierungsformat des Typs eignen, und sichergestellt werden, dass die Werte ordnungsgemäß deserialisiert werden können. Damit wird sichergestellt, dass der Wert in das binäre Format zurückkonvertiert werden kann. Bei UDTs, deren Sortierreihenfolge eine Bytereihenfolge ist, wird dadurch auch sichergestellt, dass der resultierende Binärwert dem ursprünglichen Binärwert entspricht. So wird verhindert, dass ungültige Werte in der Datenbank persistent gespeichert werden. In einigen Fällen ist diese Art der Überprüfung möglicherweise unzulänglich. Eine zusätzliche Überprüfung kann erforderlich sein, wenn UDT-Werte in einer bestimmten Domäne oder einem Bereich liegen müssen. Ein UDT beispielsweise, der ein Datum implementiert, kann erfordern, dass der Wert für den Tag eine positive Zahl ist, die in einem bestimmten zulässigen Wertebereich liegt.

Mit der Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute.ValidationMethodName-Eigenschaft des Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute können Sie den Namen einer Validierungsmethode angeben, die vom Server ausgeführt wird, wenn Daten einem UDT zugewiesen oder in eine UDT konvertiert werden. ValidationMethodName wird auch während der Ausführung des Hilfsprogramms bcp, BULK INSERT, DBCC CHECKDB, DBCC CHECKFILEGROUP, DBCC CHECKTABLE, DBCC CHECKTABLE, verteilte Abfrage und TDS-Remoteprozeduraufrufvorgänge (RPC) aufgerufen. Der Standardwert für ValidationMethodName ist NULL, was angibt, dass es keine Validierungsmethode gibt.

Beispiel

Das folgende Codefragment zeigt die Deklaration für die Point-Klasse , die einen ValidationMethodName von ValidatePoint angibt.

<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  
{  

Wenn eine Validierungsmethode angegeben wird, muss diese eine Signatur aufweisen, die etwa folgendem Codefragment entspricht:

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;  
    }  
}  

Die Validierungsmethode kann einen beliebigen Bereich aufweisen und sollte true zurückgeben, wenn der Wert gültig ist, andernfalls false . Wenn die Methode false zurückgibt oder eine Ausnahme auslöst, wird der Wert als ungültig behandelt und ein Fehler ausgelöst.

Im nachstehenden Beispiel lässt der Code für die X- und Y-Koordinaten nur Werte zu, die größer oder gleich Null sind.

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;  
    }  
}  

Einschränkungen von Validierungsmethoden

Der Server ruft die Validierungsmethode auf, wenn der Server Konvertierungen durchführt, nicht, wenn Daten durch Festlegen einzelner Eigenschaften eingefügt werden oder wenn Daten mithilfe einer Transact-SQL INSERT-Anweisung eingefügt werden.

Sie müssen die Validierungsmethode explizit über Eigenschaftensetter und die Parse-Methode aufrufen, wenn die Validierungsmethode in allen Situationen ausgeführt werden soll. Dies ist keine Voraussetzung, und in einigen Fällen ist es möglicherweise nicht einmal wünschenswert.

Beispiel für die Validierung in der Parse-Methode

Um sicherzustellen, dass die ValidatePoint-Methode in der Point-Klasse aufgerufen wird, müssen Sie sie über die Parse-Methode und die Eigenschaftenprozeduren aufrufen, die die X- und Y-Koordinatenwerte festlegen. Das folgende Codefragment zeigt, wie die Validierungsmethode ValidatePoint über die Analysefunktion aufgerufen wird.

<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;  
}  

Beispiel für die Validierung von Eigenschaften

Das folgende Codefragment zeigt, wie die Validierungsmethode ValidatePoint aus den Eigenschaftenprozeduren aufgerufen wird, die die X- und Y-Koordinaten festlegen.

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.");  
        }  
    }  
}  

Codieren von UDT-Methoden

Bei Codieren von UDT-Methoden müssen Sie berücksichtigen, ob sich der verwendete Algorithmus möglicherweise im Lauf der Zeit ändern könnte. Wenn dem so ist, sollten Sie erwägen, eine separate Klasse für die vom UDT verwendeten Methoden zu erstellen. Wenn sich der Algorithmus ändert, können Sie die Klasse mit dem neuen Code neu kompilieren und die Assembly in SQL Server laden, ohne dass sich dies auf die UDT auswirkt. In vielen Fällen können UDTs mithilfe der Alter Assembly-Anweisung von Transact-SQL neu geladen werden. Dies kann jedoch zu Problemen mit vorhandenen Daten führen. Beispielsweise verwendet der Währungs-UDT , der in der AdventureWorks-Beispieldatenbank enthalten ist, eine ConvertCurrency-Funktion zum Konvertieren von Währungswerten, die in einer separaten Klasse implementiert wird. Es ist möglich, dass sich die Konvertierungsalgorithmen in der Zukunft auf unvorhersehbare Weise ändern oder dass eine neue Funktionalität erforderlich wird. Die Trennung der ConvertCurrency-Funktion von der Currency UDT-Implementierung bietet mehr Flexibilität bei der Planung zukünftiger Änderungen.

Beispiel

Die Point-Klasse enthält drei einfache Methoden zum Berechnen der Entfernung: Distance, DistanceFrom und DistanceFromXY. Jede gibt einen Doppelten zurück, der den Abstand von Punkt zu Null, den Abstand von einem angegebenen Punkt zu Punkt und den Abstand von den angegebenen X- und Y-Koordinaten zu Punkt berechnet. Distance und DistanceFrom rufen jeweils DistanceFromXY auf und veranschaulichen die Verwendung unterschiedlicher Argumente für jede Methode.

' 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));  
}  

Verwenden von SqlMethod-Attributen

Die Microsoft.SqlServer.Server.SqlMethodAttribute-Klasse stellt benutzerdefinierte Attribute bereit, die verwendet werden können, um Methodendefinitionen zu markieren, um Determinismus bei NULL-Aufrufverhalten anzugeben und anzugeben, ob eine Methode ein Mutator ist. Bei diesen Eigenschaften werden die Standardwerte vorausgesetzt, und das benutzerdefinierte Attribut wird nur verwendet, wenn ein anderer Wert als der Standardwert erforderlich ist.

Hinweis

Die SqlMethodAttribute-Klasse erbt von der SqlFunctionAttribute-Klasse , sodass SqlMethodAttribute die Felder FillRowMethodName und TableDefinition von SqlFunctionAttribute erbt. Dies impliziert, dass es möglich ist, eine Tabellenwertmethode zu schreiben. Dies ist jedoch nicht der Fall. Die -Methode wird kompiliert, und die Assembly wird bereitgestellt, aber ein Fehler über den IEnumerable-Rückgabetyp wird zur Laufzeit mit der folgenden Meldung ausgelöst: "Methode, Eigenschaft oder Feld '<Name>' in der Klasse '<Class>' in assembly'<> hat einen ungültigen Rückgabetyp."

In der folgenden Tabelle werden einige der relevanten Microsoft.SqlServer.Server.SqlMethodAttribute-Eigenschaften beschrieben, die in UDT-Methoden verwendet werden können, und ihre Standardwerte werden aufgelistet.

DataAccess
Gibt an, ob die Funktion Zugriff auf in der lokalen Instanz von SQL Server gespeicherte Benutzerdaten einschließt. Der Standardwert ist DataAccessKind. Keine.

IsDeterministic
Gibt an, ob die Funktion bei denselben Eingabewerten und demselben Datenbankzustand auch immer dieselben Ausgabewerte erzeugt. Die Standardeinstellung lautet false.

IsMutator
Gibt an, ob die Methode eine Statusänderung in der UDT-Instanz verursacht. Die Standardeinstellung lautet false.

IsPrecise
Gibt an, ob die Funktion ungenaue Berechnungen beinhaltet, z. B. Gleitkommaoperationen. Die Standardeinstellung lautet false.

OnNullCall
Gibt an, ob die Methode aufgerufen wird, wenn als Eingabeargumente NULL-Verweise angegeben werden. Der Standardwert ist true.

Beispiel

Mit der Microsoft.SqlServer.Server.SqlMethodAttribute.IsMutator-Eigenschaft können Sie eine Methode markieren, die eine Änderung des Zustands eines instance eines UDT zulässt. Transact-SQL ermöglicht es Ihnen nicht, zwei UDT-Eigenschaften in der SET-Klausel einer UPDATE-Anweisung festzulegen. Sie können jedoch eine Methode als Mutator markieren, die zwei Elemente ändert.

Hinweis

In Abfragen sind Mutatormethoden nicht zulässig. Sie können nur in Zuweisungsanweisungen oder Datenänderungsanweisungen aufgerufen werden. Wenn eine als Mutator markierte Methode nicht void zurückgibt (oder in Visual Basic kein Sub ist), schlägt CREATE TYPE mit einem Fehler fehl.

Die folgende Anweisung setzt voraus, dass ein Dreiecks-UDT vorhanden ist, das über eine Rotate-Methode verfügt. Die folgende Transact-SQL-Update-Anweisung ruft die Rotate-Methode auf:

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

Die Rotate-Methode wird mit dem SqlMethod-Attribut ergänzt, das IsMutator auf true festlegt, sodass SQL Server die Methode als Mutatormethode markieren können. Der Code legt auch OnNullCall auf false fest, was dem Server angibt, dass die Methode einen NULL-Verweis (Nothing in Visual Basic) zurückgibt, wenn einer der Eingabeparameter NULL-Verweise sind.

<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);  
}  

Implementieren eines UDTs mit einem benutzerdefinierten Format

Wenn Sie eine UDT mit einem benutzerdefinierten Format implementieren, müssen Sie Lese - und Schreibmethoden implementieren, die die Microsoft.SqlServer.Server.IBinarySerialize-Schnittstelle implementieren, um die Serialisierung und Deserialisierung von UDT-Daten zu verarbeiten. Sie müssen auch die MaxByteSize-Eigenschaft von Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute angeben.

Der UDT Currency

Der Währungs-UDT ist in den CLR-Beispielen enthalten, die mit SQL Server installiert werden können, beginnend mit SQL Server 2005 (9.x).

Die Währungs-UDT unterstützt den Umgang mit Geldbeträgen im Geldsystem einer bestimmten Kultur. Sie müssen zwei Felder definieren: eine Zeichenfolge für CultureInfo, die angibt, wer die Währung ausgegeben hat (z. B. en-us) und ein Dezimalzeichen für CurrencyValue, den Geldbetrag.

Obwohl es vom Server nicht zum Durchführen von Vergleichen verwendet wird, implementiert currency UDT die System.IComparable-Schnittstelle , die eine einzelne Methode verfügbar macht, System.IComparable.CompareTo. Diese Methode wird auf Clientseite in Situationen verwendet, in denen Currency-Werte genau verglichen oder geordnet werden sollen.

Im Code, der in der CLR ausgeführt wird, wird die Länderangabe getrennt vom Währungswert verglichen. Für Transact-SQL-Code bestimmen die folgenden Aktionen den Vergleich:

  1. Legen Sie das IsByteOrdered-Attribut auf true fest, wodurch SQL Server angibt, die persistente binäre Darstellung auf dem Datenträger für Vergleiche zu verwenden.

  2. Verwenden Sie die Write-Methode für den Currency-UDT , um zu bestimmen, wie der UDT auf dem Datenträger beibehalten wird und wie UDT-Werte für Transact-SQL-Vorgänge verglichen und sortiert werden.

  3. Speichern Sie die Währungs-UDT mit dem folgenden Binärformat:

    1. Speichern Sie die Länderangabe als UTF-16-codierte Zeichenfolge für die Bytes 0 bis 19, wobei die Zeichenfolge rechts mit NULL-Zeichen aufgefüllt werden soll.

    2. Verwenden Sie Bytes 20 und nachfolgende Bytes zum Speichern des Dezimalwerts der Währungsbetrags.

Der Zweck der Auffüllung besteht darin, sicherzustellen, dass die Kultur vollständig vom Währungswert getrennt ist. Wenn ein UDT mit einem anderen in Transact-SQL-Code verglichen wird, werden Kulturbytes mit Kulturbytes und Währungsbytewerte mit Währungsbytewerten verglichen.

Currency-Attribute

Der Währungs-UDT wird mit den folgenden Attributen definiert.

<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  
    {  

Erstellen von Read- und Write-Methoden mit IBinarySerialize

Wenn Sie das Serialisierungsformat UserDefined auswählen, müssen Sie auch die IBinarySerialize-Schnittstelle implementieren und Ihre eigenen Lese- und Schreibmethoden erstellen. Die folgenden Verfahren aus dem Currency UDT verwenden System.IO.BinaryReader und System.IO.BinaryWriter , um aus dem UDT zu lesen und in diesen zu schreiben.

' 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();  
}  

Weitere Informationen

Erstellen eines User-Defined-Typs