Freigeben über


Programmieren benutzerdefinierter Typen

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 Codebeispiel in diesem Abschnitt veranschaulicht die Implementierung eines UDT namens Point als struct (bzw. Structure in Visual Basic). Der UDT Point 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. Der Point-UDT verwendet überdies den System.Text-Namespace zum Arbeiten mit Zeichenfolgen.

Hinweis

Visual C++-Datenbankobjekte wie UDTs, die mit /clr:pure kompiliert wurden, werden nicht für die Ausführung 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.

Die Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute ist erforderlich. Das Serializable-Attribut ist optional. Sie können auch das Microsoft.SqlServer.Server.SqlFacetAttribute-Attribut angeben, um Informationen über den Rückgabetyp eines UDTs 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 den Point-UDT auf Native fest. IsByteOrdered wird auf true festgelegt. Dies garantiert, dass Vergleiche in SQL Server dieselben Ergebnisse liefern wie Vergleiche in verwaltetem Code. Der UDT implementiert die System.Data.SqlTypes.INullable-Schnittstelle, damit der UDT NULL erkennt.

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

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 namens IsNull erstellen, mit der im CLR-Code bestimmt werden kann, ob ein Wert NULL ist. 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 eine Instanz NULL ist. Sobald der Server bestimmt, dass der UDT NULL ist, kann er seine systemeigene NULL-Behandlung verwenden.

Die get()-Methode von IsNull stellt in keiner Weise einen Sonderfall dar. Wenn eine Point-Variable @p gleich Null ist, dann ergibt @p.IsNull standardmäßig "NULL", nicht "1". Dies ist so, weil das SqlMethod(OnNullCall)-Attribut der IsNull get()-Methode den Standardwert false hat. Weil das Objekt Null ist, wird es nicht deserialisiert, wenn die Eigenschaft angefordert wird, 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. Der UDT muss auch über eine statische Eigenschaft namens Null verfügen, welche die NULL-Wertinstanz des UDTs 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 Positionen ungleich Null zurück. In Abfrage 1 wird die normale NULL-Behandlung verwendet, und dort ist keine Deserialisierung von UDTs erforderlich. In Abfrage 2 dagegen muss jedes Objekt, das nicht Null ist, deserialisiert und die CLR aufgerufen werden, um den Wert der IsNull-Eigenschaft zu erhalten. Es ist klar, dass die Verwendung IS NULL eine bessere Leistung aufweist, und es sollte nie einen Grund geben, die IsNull Eigenschaft eines UDT aus Transact-SQL-Code zu lesen.

Wozu dient also die IsNull-Eigenschaft? Erstens wird sie benötigt, damit im CLR-Code bestimmt werden kann, ob ein Wert Null ist. Zweitens muss der Server prüfen können, ob eine Instanz Null ist, und hierzu wird diese Eigenschaft vom Server verwendet. Sobald der Server bestimmt hat, dass die Instanz UDT Null ist, kann er seine systemeigene NULL-Behandlung verwenden.

Implementieren der Parse-Methode

Die Parse-Methode und die ToString-Methode ermöglichen die Konvertierung des UDT in Zeichenfolgendarstellungen und umgekehrt von Zeichenfolgen in den UDT. Die Parse-Methode lässt das Konvertieren einer Zeichenfolge in einen UDT zu. Die Zeichenfolge muss als static (oder Shared in Visual Basic) deklariert werden und einen Parameter vom Typ System.Data.SqlTypes.SqlString verwenden.

Im folgenden Code wird die Parse-Methode für den Point-UDT implementiert, welche die X- und Y-Koordinaten einer Instanz einzeln ausgibt. Die Parse-Methode verfügt über nur ein Argument des Typs System.Data.SqlTypes.SqlString und setzt voraus, dass die X- und Y-Werte in einer durch Komma begrenzten Zeichenfolge übergeben werden. Durch die Festlegung des Microsoft.SqlServer.Server.SqlMethodAttribute.OnNullCall-Attributs auf false wird verhindert, dass die Parse-Methode für eine NULL-Instanz 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 Point-UDT in einen Zeichenfolgenwert. In diesem Fall wird die Zeichenfolge "NULL" für eine NULL-Instanz des Point-Typs zurückgegeben. Die ToString-Methode kehrt das Ergebnis der Parse-Methode mithilfe eines System.Text.StringBuilder um und gibt eine durch Kommas begrenzte System.String-Instanz zurück, die aus den Koordinatenwerten X und Y 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

Der UDT Point macht die X- und Y-Koordinaten verfügbar, die als öffentliche Eigenschaften des System.Int32-Typs mit Lese-/Schreibzugriff implementiert werden.

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.

In der Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute.ValidationMethodName-Eigenschaft von Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute können Sie den Namen einer Überprüfungsmethode angeben, die der Server ausführt, wenn Daten einem UDT zugewiesen oder in einen UDT konvertiert werden. ValidationMethodName wird auch beim Ausführen des bcp-Hilfsprogramms, bei BULK INSERT, DBCC CHECKDB, DBCC CHECKFILEGROUP, DBCC CHECKTABLE und verteilten Abfragen sowie bei TDS-Vorgängen (Tabular Data Stream) und Remoteprozeduraufrufen (Remote Procedure Call, RPC) aufgerufen. Der Standardwert für ValidationMethodName lautet NULL, womit angegeben wird, dass keine Validierungsmethode festgelegt ist.

Beispiel

Das folgende Codefragment zeigt die Deklaration für die Point-Klasse, die mit ValidationMethodName als Validierungsmethode 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 Gültigkeitsbereich haben und sollte true zurückgeben, wenn der Wert zulässig ist, und andernfalls false. Wenn die Methode false zurückgibt oder eine Ausnahme auslöst, wird der Wert als nicht zulässig behandelt, und es wird ein Fehler generiert.

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 von Eigenschaftensettern und der 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 von der Parse -Methode und von den Eigenschaftenprozeduren aufrufen, die die Koordinatenwerte X und Y festlegen. Das folgende Codefragment zeigt, wie die ValidatePoint Validierungsmethode über die Parse Funktion 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 aus den ValidatePoint 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. Die in der CurrencyAdventureWorks-Beispieldatenbank enthaltene UDT verwendet beispielsweise 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 dieser Methoden gibt einen Wert vom Typ double zurück, wobei die Entfernung von Point zum Nullpunkt, die Entfernung von einem angegebenen Punkt zu Point und die Entfernung von den angegebenen X- und Y-Koordinaten zu Point berechnet wird Distanceund DistanceFrom rufen jeweils DistanceFromXY auf, und veranschaulichen, wie verschiedene Argumente für jede Methode verwendet werden.

' 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 zur Verfügung, mit denen Methodendefinitionen markiert werden können, um einen Determinismus anzugeben, das Verhalten beim Aufruf für NULL-Werte festzulegen und anzugeben, ob eine Methode eine Mutatormethode 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, daher erbt die SqlMethodAttribute-Klasse die Felder FillRowMethodName und TableDefinition von SqlFunctionAttribute. 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 Feldname><" in der Klasse "<class>" in assembly '<assembly>' hat 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 die zugehörigen Standardwerte aufgeführt.

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

IsDeterministic
Gibt an, ob die Funktion bei denselben Eingabewerten und demselben Datenbankzustand auch immer dieselben Ausgabewerte erzeugt. Der Standardwert ist false.

IsMutator
Gibt an, ob die Methode eine Statusänderung in der UDT-Instanz verursacht. Der Standardwert ist false.

IsPrecise
Gibt an, ob die Funktion ungenaue Berechnungen beinhaltet, z. B. Gleitkommaoperationen. Der Standardwert ist 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 Status einer Instanz eines UDTs gestattet. 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 Mutatormethode gekennzeichnete Methode nicht void zurückgibt (oder kein Sub in Visual Basic ist), führt CREATE TYPE zu einem Fehler.

Die folgende Anweisung setzt die Existenz des UDTs Triangles voraus, der über die 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 ist mit der SqlMethod Attributeinstellung IsMutator auf true versehen, damit SQL Server die Methode als Mutatormethode markieren kann. Im Code wird zudem OnNullCall auf false festgelegt. Dem Server wird damit angegeben, dass die Methode einen NULL-Verweis (Nothing in Visual Basic) zurückgibt, wenn einer der Eingabeparameter einen NULL-Verweis enthält.

<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

Zur Implementierung eines UDTs mit einem benutzerdefinierten Format müssen Sie die Read-Methode und die Write-Methode implementieren. Diese Methoden implementieren die Microsoft.SqlServer.Server.IBinarySerialize-Schnittstelle zur Serialisierung und Deserialisierung der UDT-Daten. Sie müssen zudem die MaxByteSize-Eigenschaft des Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute-Attributs angeben.

Der UDT Currency

Die Currency UDT ist in den CLR-Beispielen enthalten, die ab SQL Server 2005 mit SQL Server installiert werden können.

Der UDT Currency kann Währungsbeträge im Währungssystem eines bestimmten Lands verarbeiten. Sie müssen zwei Felder definieren: ein string-Feld für CultureInfo, das angibt, welches Land die Währung ausgegeben hat (beispielsweise en-us) und ein decimal-Feld für CurrencyValue, den Währungsbetrag.

Obwohl sie vom Server nicht zum Durchführen von Vergleichen verwendet wird, implementiert der UDT Currency die System.IComparable-Schnittstelle, die nur eine Methode namens System.IComparable.CompareTo bereitstellt. 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, was SQL Server angibt, die persistente binäre Darstellung auf dem Datenträger für Vergleiche zu verwenden.

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

  3. Speichern Sie den UDT Currency im folgenden binären Format:

    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 des Auffüllungsbereichs besteht darin, sicherzustellen, dass die Kultur vollständig vom Währungswert getrennt ist. Wenn ein UDT im Transact-SQL-Code mit einem anderen verglichen wird, werden Kulturbytes mit Kulturbytes verglichen und Währungsbytewerte mit Währungsbytewerten verglichen.

Befolgen Sie für die vollständige Codeauflistung für die Currency UDT die Anweisungen zum Installieren der CLR-Beispiele in SQL Server Beispiele für Datenbank-Engine.

Currency-Attribute

Der UDT Currency wurde 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 wählen, müssen Sie auch die IBinarySerialize-Schnittstelle implementieren und eigene Read- und Write-Methoden schreiben. In den folgenden Prozeduren aus dem UDT Currency werden System.IO.BinaryReader und System.IO.BinaryWriter zum Lesen bzw. zum Schreiben von UDT-Werten verwendet.

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

Die vollständige Codeauflistung für die Currency UDT finden Sie unter beispiele für SQL Server-Datenbank-Engine.

Weitere Informationen

Erstellen eines User-Defined-Typs