微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

SQL Server 用户定义的 CLR 类型可以由 String 以外的任何类型初始化吗?

如何解决SQL Server 用户定义的 CLR 类型可以由 String 以外的任何类型初始化吗?

我在 C# 中创建了一个 CLR 用户定义类型作为结构,我希望能够直接从 sql Server 中的 int 初始化这个类型。以下示例适用于字符串和空值,但对于 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 初始化结构?

解决方法

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

  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 而出错,但是如果 Value 是空引用,int_value.IsNull 将是真的。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。