Npgsql 的 IsNullable 总是 trune 而 IsAutoincrement 总是 false 吗?

Is IsNullable always trune and IsAutoincrement always false for Npgsql?

我有一个使用 VS2012 用 C# 编写的程序,它自动为数据库 tables 构建包装器 classes。我正在尝试更新它以确保智能处理空值(对我公司来说是一个新概念)。我们的大部分工作都是使用 PostgreSQL 完成的,我们通常使用 ODBC。我希望我的程序能够识别可空列和自动增量列。 DataColumn class 包括 IsNullable 和 IsAutoincrement 属性。我用每种类型的列样本创建了一些 table。使用 ODBC,发现所有列都可以为 null,并且不会自动递增。我认为那是因为 ODBC 没有实现所有功能,所以我用最新版本的 Npgsql 进行了尝试。我很惊讶地看到 Npgsql 还报告了所有可为 null 而不是自动递增的内容。我需要做些什么来设置这些属性吗?

这是我的 table 定义:

CREATE TABLE nullable_test
(
  key_field bigserial NOT NULL,
  non_nullable_integer integer NOT NULL,
  nullable_integer integer
)
WITH (
  OIDS=FALSE
);

这是我的测试程序:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Data.Odbc;

using Npgsql;

namespace NullableTest
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                NpgsqlConnection npgConn = new NpgsqlConnection();
                NpgsqlConnectionStringBuilder connStringBuilder = new NpgsqlConnectionStringBuilder();
                connStringBuilder.Host = "localhost";
                connStringBuilder.Database = "Stripco";
                connStringBuilder.Username = "caps";
                connStringBuilder.Password = "asdlkjqp";
                npgConn.ConnectionString = connStringBuilder.ToString();
                npgConn.Open();
                Console.WriteLine("Database open using Npgsql");

                DataSet npgsqlDataSet = new DataSet();
                NpgsqlDataAdapter npgsqlAdapter = new NpgsqlDataAdapter("select * from nullable_test", npgConn);
                npgsqlAdapter.Fill(npgsqlDataSet);
                Console.WriteLine("Data set is filled.");

                DataTable table = npgsqlDataSet.Tables[0];
                DataColumn keyColumn = npgsqlDataSet.Tables[0].Columns["key_field"];
                DataColumn nonNullableColumn = npgsqlDataSet.Tables[0].Columns["non_nullable_integer"];
                DataColumn nullableColumn = npgsqlDataSet.Tables[0].Columns["nullable_integer"];

                Console.WriteLine("Key column is " + (keyColumn.AutoIncrement ? "" : " not ") + " autoincrementing");
                Console.WriteLine("Key column is " + (keyColumn.AllowDBNull ? "" : " not ") + " allowing nulls.");
                Console.WriteLine("Non-nullable column is " + (nonNullableColumn.AutoIncrement ? "" : " not ") + " autoincrementing");
                Console.WriteLine("Non-nullable column is " + (nonNullableColumn.AllowDBNull ? "" : " not ") + " allowing nulls.");
                Console.WriteLine("Nullable column is " + (nullableColumn.AutoIncrement ? "" : " not ") + " autoincrementing");
                Console.WriteLine("Nullable column is " + (nullableColumn.AllowDBNull ? "" : " not ") + " allowing nulls.");

                npgConn.Close();

            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed to open database: " + ex.Message);
            }
            Console.WriteLine("Press any key");
            Console.ReadKey();
        }
    }
}

我不太了解数据table,但我的猜测是因为源是查询的结果,所以查询本身不会显示源中的列是否可为空.例如,如果您插入了联接、文字或合并视图,则确定每一列的实际来源将变得越来越困难。我不认为结果集本身知道或关心列是否可为空。

据我所知,PostgreSQL 版本 10 之前的实例没有本机标识类型。在我看来,他们完成了同样的事情,但他们将各个部分缝合在一起,就像我们过去所做的那样。因此,我不知道您是否可以确定有关专栏的内容。也就是说,如果你做出合理的假设,你可能会接近。

为了满足您的两个需求,我将继续使用 informatio_schema.columns table。像这样的东西肯定会解决可空方面,它会让你 90% 的身份:

select
  is_nullable = 'YES',
  column_default like 'nextval%'
from information_schema.columns
where
  table_schema = :SCHEMA and
  table_name = :TABLE_NAME and
  column_name = :COLUMN

C# 实现看起来像这样:

private bool IsSerial(string Schema, string Table, string Column)
{
    bool result = false;

    NpgsqlCommand cmd = new NpgsqlCommand(Resources.Sql, Connection);
    cmd.Parameters.AddWithValue("SCHEMA", Schema);
    cmd.Parameters.AddWithValue("TABLE_NAME", Table);
    cmd.Parameters.AddWithValue("COLUMN", Column);

    NpgsqlDataReader reader = cmd.ExecuteReader();

    if (reader.HasRows)
    {
        reader.Read();
        result = reader.GetBoolean(1);
    }

    reader.Close();

    return result;
}

您可以将 GetBoolean(1) 更改为 GetBoolean(0) 作为可空部分。

我的 C# 方法看起来有点粗糙,但希望它足以让你到达那里。

您必须了解在结果集上获取元数据信息(您似乎在做什么)与在 table 列上获取信息之间的区别 - 两者并不相同。

当您获取 table 的元数据时(通过 NpgsqlConnection.GetSchemaTable(),Npgsql 会去查找所有它能找到的信息,包括空能力和 auto-increment。但是,当获取有关的信息时结果集,Npgsql 几乎没有 PostgreSQL 提供的信息,也不知道它是可空的还是自动增量的。

所以要获取所有信息,请使用 NpgsqlConnection.GetSchemaTable()