SQL Server用户定义的CLR类型是否可以由字符串以外的任何类型初始化



我在C#中创建了一个CLR用户定义类型作为结构,我希望能够直接从SQL Server中的int初始化此类型。以下示例适用于字符串和null值,但对int无效,并显示消息:操作数类型冲突:int与ExhaustiveInt不兼容

CREATE TABLE ExhaustiveTest (
v ExhaustiveInt not null
);
insert into ExhaustiveTest 
values ('100'), (null), (100);

我在结构中尝试了以下操作:

using System;  
using System.Data;  
using System.Data.SqlTypes;  
using Microsoft.SqlServer.Server;
[Serializable]  
[Microsoft.SqlServer.Server.SqlUserDefinedType(
Format.Native,  
IsByteOrdered = true, 
IsFixedLength = true,
Name = "ExhaustiveInt",
ValidationMethodName = "Validate"
)]  
public struct ExhaustiveInt : INullable {  
private Int32   the_value;  
private bool    is_unknown;

public bool IsNull { 
get {
return false; 
}
}  
public static ExhaustiveInt Null {  
get {  
ExhaustiveInt an_exhaustive_int = new ExhaustiveInt();  
an_exhaustive_int.is_unknown = true;
an_exhaustive_int.the_value = 0;
return an_exhaustive_int;  
}  
}  
public ExhaustiveInt(SqlInt32 int_value) {
this.the_value = int_value.Value;
this.is_unknown = int_value.IsNull;
}
public static explicit operator ExhaustiveInt(SqlInt32 int_value) {
return new ExhaustiveInt(int_value);
}

public static ExhaustiveInt Parse(SqlString string_value) {
ExhaustiveInt v = new ExhaustiveInt();  
if(string_value.IsNull) {
v.is_unknown = true;
v.the_value = 0;
}
else {
v.is_unknown = false;
v.the_value = Int32.Parse(string_value.Value);
}
return v;
}
public override string ToString()  {  
if (this.is_unknown)  
return "Unknown";  
else 
return this.the_value.ToString(); 
}  
private bool Validate()  {  
return true;  
}  

[SqlMethod(OnNullCall = false)]  
public bool IsUnknown()  {  
return this.is_unknown;  
}  
}  

然而,SQL Server似乎忽略了特定的构造函数和运算符。有没有一种方法可以让SQL Server理解有一种方法直接从int初始化结构?

我再次检查了文档,这次注意到两件事:

  1. Parse方法需要SqlString的输入(因为目的是从字符串转换(,并且
  2. 如果UDT是在类而不是结构中定义的,则允许使用重载构造函数:

    在类中定义的UDT必须具有不接受参数的公共构造函数。您可以选择创建额外的重载类构造函数。

我已经尝试了一些方法(使用您在问题中提供的代码(,但到目前为止还无法使其按您的意愿工作。即使使用重载类构造函数,我也不确定它是否能像您希望的那样工作。我相信,使用重载构造函数的功能纯粹是为了在CLR代码中内部使用,而不是从外部T-SQL上下文访问。我相信UDT是内部实例化的(也许解释了构造函数不带参数的要求(,因此在我们与它们交互时已经存在,即使是在DECLARE语句中。意思是,我们可以这样称呼它:

  1. DECLARE @Int dbo.ExhaustiveInt = NULL;
    DECLARE @Int dbo.ExhaustiveInt = 5;
    
    这两者都调用Parse方法
  2. DECLARE @Int dbo.ExhaustiveInt = 0x1234567801;
    -- This is usually in the form of passing in another variable
    -- of the same UDT, or setting via: @Var = @Var.Method(val);
    
    它通过Read方法反序列化值(使用Format.Native时在内部处理,使用Format.UserDefined时需要(

在这两种情况下,类型都已存在,以便调用ParseRead


此外,我不认为它会使用这个:

public ExhaustiveInt(SqlInt32 int_value) {
this.the_value = int_value.Value;
this.is_unknown = int_value.IsNull;
}

如果是这样,并且传入了NULL,则会出错,因为您没有检查IsNull,但如果int_value.IsNull为true,则Value将是空引用。

相关内容

最新更新