【问题标题】:How to correctly store C#'s Bitarray in Postgres table如何在 Postgres 表中正确存储 C# 的 Bitarray
【发布时间】:2020-04-04 01:01:44
【问题描述】:

目前我正在尝试将可变长度的位模式存储在 Postgres 表中。我的用例是我想以紧凑的方式对有关分配给组的数据记录的一些信息进行编码。

我在 Postgres 中的表的简化架构如下所示:

CREATE TABLE axivas.group_records (
id int4 NOT NULL GENERATED ALWAYS AS IDENTITY,
record_id int4 NOT NULL,
group_ids varbit(50) NOT NULL,
CONSTRAINT group_records_pkey PRIMARY KEY (id));

在 C# 应用程序中,我使用 Npgsql Entity FrameworkCore 创建实体,如下所示:

try
{
     var context = new xerxesdevtestsContext();

     Random rnd = new Random();

     for (int i = 0; i < 1024; i++)
     {

        BitArray ba = new BitArray(rnd.Next(10, 50));
        ba.SetAll(false);
        for (int j=rnd.Next(0,5);j<rnd.Next(5,ba.Length-1);j++)
        {
            ba[j] = true;
        }
        context.GroupRecords.Add(new GroupRecords()
        {
            GroupIds = ba,
            RecordId = i
        });

     }
     context.SaveChanges();
 }
 catch (Exception ex)
 {
     Console.WriteLine("Error: " + ex.Message);
 }

在 porpose 上添加了随机数,用于设置位的数量和位数组的长度。

当我查看存储的数据时,我可以看到在某些情况下,位字符串存储时带有前导零,在其他情况下,前导零被省略(我附上了 screenshot 来说明这一点)。换句话说,在某些情况下,DBeaver 会显示像“0000110110111110000.....”这样的值,在其他情况下会显示像“1100111...”这样的值。

所以我的问题是,如何解释这一点以及是否可以完全省略位字符串中的前导零?

任何想法或额外信息将不胜感激。

更新: 我更改了表中位字符串的大小并

将位数组中的各个位设置位并再次测试的算法。我的更改具有以下效果:

  1. 位数组将从最高索引开始填充。
  2. 在结果事件中可以观察到更多的前导零;例如这是结果记录之一:

|3104 |702 |000000000000000000000000000000000000000000000000000000000000000000000011111111111111111110 |

我认为这种情况清楚地表明了为什么我要省略前导零。

最好的问候,

迈克尔

【问题讨论】:

    标签: c# postgresql bitarray


    【解决方案1】:

    很明显,您的位数组具有前导零的原因是因为在您的for 循环中,j 被初始化为某个很少为零的值。 j 必须始终为零才能开始在数组的开头放置 1。否则,在大多数情况下,您最终会得到前导零。

    所以,如果你想要可变长度的随机二进制数,为什么不这样做:

    BitArray ba = new BitArray(rnd.Next(10, 50));
    
    ba.SetAll(false);
    ba[0] = true;
    
    for (int j = 1; j < ba.Length - 1; j++)
    {
        ba[j] = Convert.ToBoolean(rnd.Next(2));
    }
    

    创建的示例值:

    100110101001000011111100110100010101100110110
    111101100110001101001100111101001100011110
    1010101111000100
    1011001010001000010100
    101001101001010100101110000001000111001010
    

    【讨论】:

    • 是的,对于 C# 方面的问题,这很明显。实际上,在 C# 方面,已经生成了前导零,以便能够检查 Postgres 如何存储位字符串。也许我应该更精确。我想知道为什么 PostgreSQL 存储前导零。它们不携带任何有价值的信息,所以我的理解是,当 varbit 用作列中的数据类型时,它们没有被存储。但是,似乎将存储任何指定的位,并且 varbit 字段的长度仅定义最大长度。我的理解正确吗?
    • @NightFlyer35 是的,这令人困惑。您真正的问题可能很简单“为什么 PostgreSQL 在 varbit 列中存储前导零”。您可能完全隐藏了涉及 C# 的事实,只是展示了几个手动将二进制序列插入数据库的示例。在回答这个问题时,varbit 并没有声称自己是二进制数表示,它只是声称拥有位序列。我相信在某些情况下我们会合理地想要前导零。
    • 对@robbpriestley 的困惑感到抱歉。考虑到您的 cmets,我使用一个小助手类解决了我的问题,该类负责处理正确长度的位字段。
    猜你喜欢
    • 1970-01-01
    • 2021-06-25
    • 2021-11-27
    • 2019-01-24
    • 2022-11-21
    • 2017-09-01
    • 1970-01-01
    • 2011-11-16
    • 2015-05-20
    相关资源
    最近更新 更多