我在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
初始化结构?
我再次检查了文档,这次注意到两件事:
Parse
方法需要SqlString
的输入(因为目的是从字符串转换(,并且- 如果UDT是在类而不是结构中定义的,则允许使用重载构造函数:
在类中定义的UDT必须具有不接受参数的公共构造函数。您可以选择创建额外的重载类构造函数。
我已经尝试了一些方法(使用您在问题中提供的代码(,但到目前为止还无法使其按您的意愿工作。即使使用重载类构造函数,我也不确定它是否能像您希望的那样工作。我相信,使用重载构造函数的功能纯粹是为了在CLR代码中内部使用,而不是从外部T-SQL上下文访问。我相信UDT是内部实例化的(也许解释了构造函数不带参数的要求(,因此在我们与它们交互时已经存在,即使是在DECLARE
语句中。意思是,我们可以这样称呼它:
这两者都调用DECLARE @Int dbo.ExhaustiveInt = NULL; DECLARE @Int dbo.ExhaustiveInt = 5;
Parse
方法
它通过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
时需要(
在这两种情况下,类型都已存在,以便调用Parse
或Read
。
此外,我不认为它会使用这个:
public ExhaustiveInt(SqlInt32 int_value) {
this.the_value = int_value.Value;
this.is_unknown = int_value.IsNull;
}
如果是这样,并且传入了NULL
,则会出错,因为您没有检查IsNull
,但如果int_value.IsNull
为true,则Value
将是空引用。