无法从 SQL Server VARBINARY(MAX) 列检索 C# BitArray

问题描述 投票:0回答:1

使用 SQL Server 和 SSMS,如何从 SQL Server

BitArray
列读取用 C# 创建的
VARBINARY(MAX)

有几个人发布了 Sql Server 按位运算符的解释或数据库规范化文章的链接。 这并不能回答这个问题。我没有使用位标志;我也没有兴趣在表中创建无数的位列。我正在存储一个 C# BitArray,它可以在 SqlServer VARBINARY(MAX) 字段中包含数百到数千个值。 BitArray 类似于通用的

List<bool>
,只不过它是经过优化的。我可以轻松地在 C# 中重构并读取这个位数组。我有兴趣了解是否有一种方法可以从 Sql Server 存储过程中的这个位数组读取并确定索引“x”处的项目是真还是假。感谢任何知道这是否可行并可以提供如何做到这一点的示例的人。

使用 C#,我正在创建一个像这样的

BitArray

var bitArray = new BitArray(2);

我正在设置这样的位:

bitArray[0] = true;
bitArray[1] = false;

...等等。

我将

bitArray
发送到 SQL Server 存储过程,并将其保存到
VARBINARY(MAX)
列中。我在 C# 中创建的
SqlParameter
看起来像这样:

var byteArray = new byte[2]; 
bitArray.CopyTo(byteArray,0);   
new SqlParameter("@BitArray", SqlDbType.VarBinary) { Size=-1, Value = byteArray }

在我的存储过程中,我将

@BitArray
保存到
VARBINARY(MAX)
列。保存后,我可以从 C# 应用程序的表中检索该值,并从重构的位数组中读取各个 true/false 项。这一切都很好。

我使用

打开
SqlDataReader

SELECT MyByteArray FROM MyTable WHERE Id = @MyId

我在数据读取器中获取字节数组并将其转换为位数组:

Byte[] myByteArray = (byte[])reader.GetValue(0);
BitArray myReconstitutedBitArray = new BitArray(myByteArray)

然后我可以从

myReconstitutedBitArray
中读取内容,发现一切正常:

  • myReconstitutedBitArray[0] = true。
  • myReconstitutedBitArray[1] = false。

等等。一切正常。

问题是,在 SQL Server 中,我需要能够从

MyTable.MyByteArray
读取并查看各个真/假值,但我不能。一切都返回错误。我使用的是 SQL Server 2022,因此我使用
GET_BIT
方法,但它对所有内容都返回 false。无论我在索引位置放什么,它都会返回 false。我知道该字段具有正确的值,因为我可以在 C# 中读取它们。

如何在 SQL Server 中读取这些值?

每次这样的调用都会返回 false,即使我知道该位是 true 并且我可以在 C# 中看到真实值:

SELECT GET_BIT(MyByteArray, 0) FROM MyTable WHERE MyId = @MyId
SELECT GET_BIT(MyByteArray, 1) FROM MyTable WHERE MyId = @MyId
c# sql-server byte bit
1个回答
0
投票

不幸的是,C#

BitArray
和 SQL Server 的
GET_BIT
只是工作方式有点不同。 因此,需要采取一些措施来以最小的摩擦在两者之间进行映射(C# 比 SQL 更灵活,因此更容易解决 C# 中的不匹配问题)

  • 一些尴尬的 SQL 代码
  • 一些尴尬的 C# 代码(可以创建辅助扩展方法)
  • 自己序列化BitArray(可以复制源代码并修改/邪恶的私有变量访问)
  • 编写您的 BitArray 类

推荐

我只是添加一些辅助扩展方法到

BitArray

public static class BitArrayExtension
{
    public static bool GET_BIT(this BitArray bitArray, int offset)
        => bitArray.Get(bitArray.Length - 8 - (offset & 0xF8) + (offset & 0x7));

    public static void SET_BIT(this BitArray bitArray, int offset, bool value)
        => bitArray.Set(bitArray.Length - 8 - (offset & 0xF8) + (offset & 0x7), value);
}

var myBitArray = new BitArray(24);
myBitArray.SET_BIT(6, true)
myBitArray.GET_BIT(6) // == SELECT GET_BIT(MyBitArray, 6) FROM ...

显示
/**/
中的 SQL Server 和
[]

中的 BitArray 之间的区别
var flags = new BitArray(24)
{
    //       0x01 == 0b0000_0001 ~ GET_BIT(MyByteArray, 16)
    /* 16 */ [00] = true, // <--
    /* 17 */ [01] = !true,
    /* 18 */ [02] = !true,
    /* 19 */ [03] = !true,
    /* 20 */ [04] = !true,
    /* 21 */ [05] = !true,
    /* 22 */ [06] = !true,
    /* 23 */ [07] = !true,
    
    //       0x04 == 0b0000_0100 ~ GET_BIT(MyByteArray, 10)
    /* 08 */ [08] = !true,
    /* 09 */ [09] = !true,
    /* 10 */ [10] = true,  // <--
    /* 11 */ [11] = !true,
    /* 12 */ [12] = !true,
    /* 13 */ [13] = !true,
    /* 14 */ [14] = !true,
    /* 15 */ [15] = !true,

    //       0x40 == 0b0100_0000 ~ GET_BIT(MyByteArray, 6)
    /* 00 */ [16] = !true,
    /* 01 */ [17] = !true,
    /* 02 */ [18] = !true,
    /* 03 */ [19] = !true,
    /* 04 */ [20] = !true,
    /* 05 */ [21] = !true,
    /* 06 */ [22] = true, // <--
    /* 07 */ [23] = !true
};
var byteArray = new byte[flags.Length / 8];
flags.CopyTo(byteArray, 0); // will write out => 0x010440 (this is what you will see in SQL Server)

如何绘制地图

注意映射之间的对称性(例如

/* 06 */ [22]
/* 22 */ [06]
),因此我们只需要一个函数 双向转换

int SqlServerOffset(int bitArrayOffset) => (myBitArray.Length / 8 - bitArrayOffset / 8 - 1) * 8 + bitArrayOffset % 8
int BitArrayOffset(int sqlServerOffset) => (myBitArray.Length / 8 - sqlServerOffset / 8 - 1) * 8 + sqlServerOffset % 8
// same as above but using bit operations
int SqlServerOffset(int bitArrayOffset) => myBitArray.Length - 8 - (bitArrayOffset & 0xF8) + (bitArrayOffset & 0x7)


(LEN(MyBitArray) - @BitArrayOffset/8 - 1) * 8 + (@BitArrayOffset % 8) SqlServerOffset
LEN(MyBitArray)<<3 - 8 - (@BitArrayOffset & 0xF8) + (@BitArrayOffset & 0x7) SqlServerOffset
© www.soinside.com 2019 - 2024. All rights reserved.