如何获取ADO.NET中的主键列?

时间:2017-01-23 16:16:41

标签: c# ado.net

我有一张桌子:

CREATE TABLE [dbo].[DeliveryData](
    [DeliveryId] [int] IDENTITY(1,1) NOT NULL,
   ...
CONSTRAINT [PK_DeliveryData] PRIMARY KEY CLUSTERED 
(
    [DeliveryId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

代码:

public void GetPrimaryKeyColumns(SqlConnection conn) {
    SqlCommand cmd = conn.CreateCommand();
    cmd.CommandText = "select * from [dbo].[DeliveryData]";
    SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SchemaOnly);
    DataTable schema = reader.GetSchemaTable();
    DataColumn[] columns = schema.PrimaryKey;
    ...
}

cmd,reader和schema看起来都很好,但是列的结尾是零长度数组。不应该包含" DeliveryId"?如何获得主要列" DeliveryId"?

感谢您的帮助!

布雷克

3 个答案:

答案 0 :(得分:0)

架构表不是DeliveryData表。您必须检查IsKey列为true的架构表,然后抓取ColumnName字段。然后,您可以使用它在常规数据表中查找实际列。

  

更新

GetSchemaTable()会返回元数据信息的数据表,您可以在文档中看到:https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.getschematable(v=vs.110).aspx

如果要运行查询,最终返回的DataTable中的行数与查询中的列数一样多。这是我从数据库中的测试表中获得的模式表的部分屏幕截图。请注意,每列现在都是一行,IsKey字段将告诉您列是否为键列: enter image description here

如果您想在DataTable上使用PrimaryKey属性,请不要使用GetSchemaTable(),只需使用SqlDataAdapter填充常规DataTable。

  

更新2

使用CommandBehavior.KeyInfo代替CommandBehavior.SchemaOnly

  

使用SMO

using Microsoft.SqlServer.Management.Smo;
....

Server svr = new Server("Your Server Name");
Database db = svr.Databases["Your Database Name"];
Table tbl = db.Tables["DeliveryData"];
foreach (Column c in tbl.Columns)
{
    bool isAKeyColumn = c.InPrimaryKey

}

答案 1 :(得分:0)

使用GetSchemaTable,MSSQL在所有情况下都不会返回正确的主键信息。 (并不太令人惊讶。例如,几乎所有数据库供应商都支持ODBC比MS更好。)但是,以下查询确实有效:

SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS as tc
LEFT JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE as  kcu
    ON kcu.CONSTRAINT_CATALOG = tc.CONSTRAINT_CATALOG
    AND kcu.CONSTRAINT_SCHEMA = tc.CONSTRAINT_SCHEMA
    AND kcu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME
    AND kcu.TABLE_CATALOG = tc.TABLE_CATALOG
    AND kcu.TABLE_SCHEMA = tc.TABLE_SCHEMA
    AND kcu.TABLE_NAME = tc.TABLE_NAME
WHERE tc.CONSTRAINT_TYPE ='PRIMARY KEY'
    AND tc.TABLE_SCHEMA = 'dbo'
    AND tc.TABLE_NAME = 'DeliveryData'
ORDER BY ORDINAL_POSITION;

答案 2 :(得分:0)

这是一个完整的解决方案:

public List<string> GetPrimaryKeyColumns(DbConnection conn, string schema, string table) {
    DbCommand cmd = conn.CreateCommand();

    DbParameter p = cmd.CreateParameter();
    p.ParameterName = "@schema";
    p.Value = schema;
    p.DbType = DbType.String; 
    p.Direction = ParameterDirection.Input;
    cmd.Parameters.Add(p);

    p = cmd.CreateParameter();
    p.ParameterName = "@table";
    p.Value = table;
    p.DbType = DbType.String;
    p.Direction = ParameterDirection.Input;
    cmd.Parameters.Add(p);

    cmd.CommandText = @"SELECT kcu.COLUMN_NAME
                        FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS as tc
                        LEFT JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE as  kcu
                            ON kcu.CONSTRAINT_CATALOG = tc.CONSTRAINT_CATALOG
                               AND kcu.CONSTRAINT_SCHEMA = tc.CONSTRAINT_SCHEMA
                               AND kcu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME
                               -- AND kcu.TABLE_CATALOG = tc.TABLE_CATALOG  doesn't work on MySQL
                               AND kcu.TABLE_SCHEMA = tc.TABLE_SCHEMA
                               AND kcu.TABLE_NAME = tc.TABLE_NAME
                        WHERE tc.CONSTRAINT_TYPE ='PRIMARY KEY'
                              AND tc.TABLE_SCHEMA = @schema
                              AND tc.TABLE_NAME = @table
                        ORDER BY ORDINAL_POSITION";

    DbDataReader reader = cmd.ExecuteReader(CommandBehavior.KeyInfo);

    List<string> res = new List<string>();
    while (reader.Read()) {
        var str = reader[0];
        if (str != System.DBNull.Value)
            res.Add((string) str);
    }
    reader.Dispose();
    cmd.Dispose();
    return res;
}