如何正确序列化可排序的SQLCLR用户定义类型?

Mat*_*int 5 .net c# sql-server sorting sqlclr

我在C#中构建自定义用户定义类型以与SQL CLR一起使用.请参阅此参考.

底层数据可以使用常规带符号的32位整数以4个字节表示.这是实施:

[Serializable]
[SqlUserDefinedType(Format.UserDefined, IsByteOrdered = true,
                    IsFixedLength = true, MaxByteSize = 4)]
public struct MyUDT : INullable, IBinarySerialize
{
    private int _value;

    public int Value
    {
        get { return _value; }
    }

    public MyUDT(int value)
        : this()
    {
        _value = value;
    }

    public override string ToString()
    {
        return _value.ToString(CultureInfo.InvariantCulture);
    }

    [SqlMethod(OnNullCall = false)]
    public static MyUDT Parse(SqlString s)
    {
        int i = int.Parse(s.Value);
        return new MyUDT(i);
    }

    public bool IsNull { get; private set; }
    public static MyUDT Null
    {
        get { return new MyUDT { IsNull = true }; }
    }

    public void Read(BinaryReader r)
    {
        var bytes = r.ReadBytes(4);

        if (BitConverter.IsLittleEndian)
            Array.Reverse(bytes);

        int i = BitConverter.ToInt32(bytes, 0);
        _value = i ^ unchecked((int) 0x80000000);
    }

    public void Write(BinaryWriter w)
    {
        int i = _value ^ unchecked((int) 0x80000000);
        var bytes = BitConverter.GetBytes(i);

        if (BitConverter.IsLittleEndian)
            Array.Reverse(bytes);

        w.Write(bytes);
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,我将添加其他方法,使其更有用,但这是编译和发布的最小值.

我需要确保当这种类型用于比较时,例如当它是表中的列时,它是正确排序的.将有正面和负面的价值观.

正如您所看到的,我不得不反转字节顺序,因为字节顺序是向后的.我还必须调整字节,以便将零表示为0x80000000,并且-1变为0x7FFFFFFF.否则,值无法正确排序.

但是,这不是 SQL Server整数正常工作的方式.例如:

SELECT convert(varbinary, -16)  -- 0xFFFFFFF0
SELECT convert(varbinary, 16)   -- 0x00000010
Run Code Online (Sandbox Code Playgroud)

然而这些都很好!所以我只能得出结论,除了原始的字节顺序之外还有其他排序类型.但我找不到任何方法来控制我的UDT.可能吗?

我发现的所有例子都显示如下:

public void Read(BinaryReader r)
{
    _value = r.ReadInt32();
}

public void Write(BinaryWriter w)
{
    w.Write(_value);
}
Run Code Online (Sandbox Code Playgroud)

但是它以完全不同的格式写入.它就像SQL Server的格式,但是字节顺序是相反的(1是0x01000000和-16是0xF0FFFFFF).所以事情排序完全错误.那些例子错了吗?某处有错误吗?

我还考虑过使用Format.Native和省略自定义序列化.这样的工作,但我最终得到5字节值,其中零看起来像0x8000000000-1看起来像0x7FFFFFFF00.它像我一样自动转换,但它为IsNull布尔字段存储了一个额外的字节.它不会接受标记为[NonSerialized],并且不会让我删除它.可空性是一项要求,因此它必须存在.

当然有比简单操作更简单的方法吗?

另一个问题是我的类型不能直接转换为intSQL内部.虽然,我不确定我是否需要.

另请参阅关于DBA.SE 的相关(但不同)问题.

Rob*_*Kee 0

我怀疑您想实现 IComparable 并将 IsByteOrdered 设置为 false。0x80000000这将消除通过将零转换为并将 -1转换为 来玩游戏的需要07FFFFFFF

最后我要说的是,我什至不是这方面的初学者。我自己从来没有这样做过,但我浏览了这里的文档:http ://msdn.microsoft.com/en-us/library/ms131082.aspx