5

ADO.NETメソッドを使用して列が主キーであるかどうかを判断する方法はありGetSchemaますか?

これが私がこれまでに得たものです:

public IEnumerable<DbColumnInfo> GetColumns(string providerName, string connectionString, string tableName)
{
    DbProviderFactory factory = DbProviderFactories.GetFactory(providerName);
    using (DbConnection connection = factory.CreateConnection())
    using (DbCommand command = factory.CreateCommand())
    {
        connection.ConnectionString = connectionString;
        connection.Open();
        command.Connection = connection;

        var columns = connection.GetSchema("Columns", tableName.Split('.'));
        foreach (DataRow row in columns.Rows)
        {
            yield return new DbColumnInfo()
            {
                Name = row.Field<string>(3),
                OrdinalPosition = row.Field<short>(4),
                DataType = this.FormatDataType(row),
                IsNullable = string.Equals(row.Field<string>(6), "yes", StringComparison.InvariantCultureIgnoreCase),
                IsPrimaryKey = // ... ?
            };
        }
    }
}
4

6 に答える 6

4

connection.GetSchema()..で判断できないのではないかと思います。

ただし、回避策として、適切な場合はデータアダプターを試すことができます。

    var da = factory.CreateDataAdapter();
    command.CommandText = "select * from Employees";
    da.SelectCommand = command;
    da.MissingSchemaAction = MissingSchemaAction.AddWithKey;

    var dtab = new DataTable();
    da.FillSchema(dtab, SchemaType.Source);

    foreach (DataColumn col in dtab.Columns)
    {
        string name = col.ColumnName;
        bool isNull = col.AllowDBNull;
        bool isPrimary = dtab.PrimaryKey.Contains(col);
    }
于 2013-03-04T18:30:38.837 に答える
3

qesが尋ねたので、私が現在使用しているもの(Laszloが彼の実用的なソリューションを提供してからコードをリファクタリングした後)は、私が望んでいたほどエレガントではありませんでしたが、より効率的で私のニーズを満たしました。基本的に、私は特定のプロバイダー向けにDbInfoProvider作成するように設計されたクラスを提供します。はこれを使用して、SQLServerの列情報のみを取得します。DbTableInfoDbColumnInfoSqlDbInfoProvider

public IEnumerable<DbColumnInfo> GetColumns(string connectionString, DbTableInfo table)
{
    DbProviderFactory factory = DbProviderFactories.GetFactory(this.providerName);
    using (DbConnection connection = factory.CreateConnection())
    using (DbCommand command = factory.CreateCommand())
    {
        connection.ConnectionString = connectionString;
        connection.Open();
        command.Connection = connection;
        command.CommandText = ColumnInfoQuery;
        command.CommandType = CommandType.Text;
        var tableSchema = factory.CreateParameter();
        tableSchema.ParameterName = "@tableSchema";
        tableSchema.DbType = DbType.String;
        tableSchema.Value = table.Schema;
        command.Parameters.Add(tableSchema);
        var tableName = factory.CreateParameter();
        tableName.ParameterName = "@tableName";
        tableName.DbType = DbType.String;
        tableName.Value = table.Name;
        command.Parameters.Add(tableName);

        var dataTable = new DataTable();
        using (var reader = command.ExecuteReader())
        {
            while (reader.Read())
            {
                yield return new DbColumnInfo()
                {
                    Name = reader.GetString(0),
                    OrdinalPosition = reader.GetInt32(1),
                    DataType = reader.GetString(2),
                    IsNullable = reader.GetBoolean(3),
                    IsPrimaryKey = reader.GetBoolean(4),
                    IsForeignKey = reader.GetBoolean(5),
                    IsUnique = reader.GetBoolean(6),
                };
            }
        }
    }
}

ColumnInfoQueryこのような静的文字列はどこにありますか?

SELECT c.[column_name]
     , CAST(c.[ordinal_position] AS int) [ordinal_position]
     , CASE WHEN c.[data_type] IN ( 'bit', 'date', 'datetime', 'smalldatetime', 'int', 'bigint', 'smallint', 'tinyint', 'real', 'money', 'smallmoney', 'image', 'text', 'ntext' )  THEN c.[data_type]
            WHEN c.[character_maximum_length] IS NOT NULL
            THEN c.[data_type] + '(' + CAST(c.[character_maximum_length] AS VARCHAR(30)) + ')'
            WHEN c.[datetime_precision] IS NOT NULL 
            THEN c.[data_type] + '(' + CAST(c.[datetime_precision] AS VARCHAR(30)) + ')'
            WHEN c.[numeric_scale] IS NOT NULL 
            THEN c.[data_type] + '(' + CAST(c.[numeric_precision] AS VARCHAR(30)) + ',' + CAST(c.[numeric_scale] AS VARCHAR(30)) + ')'
            WHEN c.[numeric_precision] IS NOT NULL 
            THEN c.[data_type] + '(' + CAST(c.[numeric_precision] AS VARCHAR(30)) + ')'
            ELSE c.[data_type]
       END [data_type]
     , CAST(MAX(CASE c.[is_nullable] WHEN 'YES' THEN 1 ELSE 0 END) AS bit) [is_nullable]
     , CAST(MAX(CASE WHEN pk.[constraint_type] = 'PRIMARY KEY' THEN 1 ELSE 0 END) AS bit) [is_primary_key]
     , CAST(MAX(CASE WHEN pk.[constraint_type] = 'FOREIGN KEY' THEN 1 ELSE 0 END) AS bit) [is_foreign_key]
     , CAST(MAX(CASE WHEN pk.[constraint_type] = 'FOREIGN KEY' THEN 0 ELSE 1 END) AS bit) [is_unique]
FROM information_schema.columns c
LEFT JOIN information_schema.constraint_column_usage ccu 
        ON c.[column_name] = ccu.[column_name] 
        AND c.[table_name] = ccu.[table_name] 
        AND c.[table_schema] = ccu.[table_schema]
        AND c.[table_catalog] = ccu.[table_catalog]
LEFT JOIN information_schema.table_constraints pk 
        ON pk.[constraint_name] = ccu.[constraint_name]
        AND pk.[table_name] = ccu.[table_name] 
        AND pk.[constraint_schema] = ccu.[table_schema]
        AND pk.[constraint_catalog] = ccu.[table_catalog]
        AND pk.[constraint_type] IN ( 'PRIMARY KEY', 'FOREIGN KEY', 'UNIQUE' )
WHERE c.[table_schema] = @tableSchema
        AND c.[table_name] = @tableName
GROUP BY c.[table_schema], c.[table_name], c.[column_name], c.[ordinal_position]
       , c.[data_type], c.[character_maximum_length], c.[datetime_precision]
       , c.[numeric_precision], c.[numeric_scale], c.[is_nullable]
于 2014-04-30T16:26:30.553 に答える
2

はい、インデックスのスキーマをリクエストすることで、どの列が主キーであるかを判断できます。次に、特定の列/テーブルのインデックスを検索します

DataTable indexes = conn.GetSchema("Indexes");
List<string> PrimaryKeys = new List<string>();
foreach (DataRow row in indexes.Rows)
  if (Convert.ToBoolean(row["PRIMARY_KEY"]))
    PrimaryKeys.Add(row["TABLE_NAME"] + "." + row["COLUMN_NAME"]);

PrimaryKeysには、データベース内の主キーのリストが含まれます。[テーブル]。[列]がこのリストにあるかどうかを確認するだけです。

于 2014-09-01T18:33:10.873 に答える
0

これはSQLITEおよびおそらく他のデータベースで機能します:-

            string[] restrictions = new string[] { null, null,   strTable };
            DataTable tableInfo = Connection.GetSchema("IndexColumns", restrictions);

            if (tableInfo == null)
                throw new Exception("TableInfo null Error");

            foreach (DataRow test in tableInfo.Rows)
            {
                Console.WriteLine(test["column_name"]);             
            }
于 2014-03-10T22:42:48.437 に答える
0

少なくともOracleODP.Netプロバイダーには、GetSchema()の「PrimaryKeys」オプションがあります。パラメータを指定せずにGetSchema()を使用して、実装に定義されている他の呼び出しを確認することをお勧めします。このコードは、Oracleプロバイダーに対して実装された他のGetSchema()呼び出しを記述するGetSchema()メタ定義を取得します。

    private void GetSchemaMetaInfo(DbConnection connection)
    {
        var metaDataCollections = connection.GetSchema("MetaDataCollections");
        var dataSourceInformation = connection.GetSchema("DataSourceInformation");
        var dataTypes = connection.GetSchema("DataTypes");
        var restrictions = connection.GetSchema("Restrictions");
        var reservedWords = connection.GetSchema("ReservedWords");
    }
于 2014-10-28T15:37:03.243 に答える
0

PrimaryKeysコレクションを使用して、特定のテーブルの主キーを判別し、対応するインデックス名を取得して、IndexColumnsコレクションからインデックスと主キーを構成する列を取得することができます。

String pkIndxNm = null;
List<String> lstPkColNms = new List<String>();

DataTable dt = dbConn.GetSchema("PrimaryKeys", new[] { owner, tblNm });
if (dt.Rows.Count == 1) {
    DataRow pkRow = dt.Rows[0];
    pkIndxNm = pkRow["INDEX_NAME"] as String;

    // Now use the IndexColumns collection to pick up the names of the 
    // columns which constitute the primary key.
    //
    dt = dbConn.GetSchema("IndexColumns", new[] { owner, pkIndxNm });
    foreach (DataRow icRow in dt.Rows) {
        String colNm = icRow["COLUMN_NAME"] as String;
        lstPkColNms.Add(colNm);
    }
}

これは、基礎となるSystem.Data.OracleClient接続でSystem.Data.Common.DbConnectionクラスを使用するOracleデータベースに対して機能しました。

他のデータベースの場合、引数として渡すことができるものについて、Restrictionsコレクションを調べる必要がある場合があります。GetSchemaの制限に関するドキュメントはかなり役に立たないようです。制限コレクションのDataTableをダンプするだけで、各コレクションを最適に照会する方法を理解できることがわかりました。

  DataTable dt = dbConn.GetSchema("Restrictions");
  AppLog.Log.Info("CollectionName | RestrictionName | ParameterName | " +
                  "RestrictionDefault | RestrictionNumber");
  AppLog.Log.Info(" ");
  foreach (DataRow r in dt.Rows) {
      String s = r["CollectionName"] as String;
      s += " | " + r["RestrictionName"] as String;
      s += " | " + r["ParameterName"] as String;
      s += " | " + r["RestrictionDefault"] as String;
      s += " | " + r["RestrictionNumber"].ToString();
      AppLog.Log.Info(s);
  }

これが私が得たものであり、そこから、配列の1番目と2番目の位置にownerとindexNameを渡して、適切なインデックスに制約することがわかりました。

ユーザー| ユーザー名| 名前| ユーザー名| 1

テーブル| 所有者| 所有者| 所有者| 1

テーブル| テーブル| テーブル名| TABLE_NAME | 2

列| 所有者| 所有者| 所有者| 1

列| テーブル| テーブル名| TABLE_NAME | 2

列| コラム| COLUMNNAME | COLUMN_NAME | 3

ビュー| 所有者| 所有者| 所有者| 1

ビュー| 表示| ビューネーム| VIEW_NAME | 2

同義語| 所有者| 所有者| 所有者| 1

同義語| 同義語| SYNONYMNAME | SYNONYM_NAME | 2

シーケンス| 所有者| 所有者| SEQUENCE_OWNER | 1

シーケンス| シーケンス| シーケンス| SEQUENCE_NAME | 2

ProcedureParameters | 所有者| 所有者| 所有者| 1

ProcedureParameters | ObjectName | オブジェクト名| OBJECT_NAME | 2

関数| 所有者| 所有者| 所有者| 1

関数| 名前| 名前| OBJECT_NAME | 2

IndexColumns | 所有者| 所有者| INDEX_OWNER | 1

IndexColumns | 名前| 名前| INDEX_NAME | 2

IndexColumns | TableOwner | TABLEOWNER | TABLE_OWNER | 3

IndexColumns | TableName | テーブル名| TABLE_NAME | 4

IndexColumns | コラム| COLUMNNAME | COLUMN_NAME | 5

インデックス| 所有者| 所有者| 所有者| 1

インデックス| 名前| 名前| INDEX_NAME | 2

インデックス| TableOwner | TABLEOWNER | TABLE_OWNER | 3

インデックス| TableName | テーブル名| TABLE_NAME | 4

パッケージ| 所有者| 所有者| 所有者| 1

パッケージ| 名前| パッケージ名| OBJECT_NAME | 2

PackageBodies | 所有者| 所有者| 所有者| 1

PackageBodies | 名前| 名前| OBJECT_NAME | 2

引数| 所有者| 所有者| 所有者| 1

引数| PackageName | パッケージ名| PACKAGE_NAME | 2

引数| ObjectName | オブジェクト名| OBJECT_NAME | 3

引数| ArgumentName | ARGUMENTNAME | ARGUMENT_NAME | 4

手順| 所有者| 所有者| 所有者| 1

手順| 名前| 名前| OBJECT_NAME | 2

UniqueKeys | 所有者| 所有者| 所有者| 1

UniqueKeys | Table_Name | テーブル名| TABLE_NAME | 2

UniqueKeys | Constraint_Name | CONSTRAINTNAME | CONSTRAINT_NAME | 3

PrimaryKeys | 所有者| 所有者| 所有者| 1

PrimaryKeys | Table_Name | テーブル名| TABLE_NAME | 2

PrimaryKeys | Constraint_Name | CONSTRAINTNAME | CONSTRAINT_NAME | 3

ForeignKeys | Foreign_Key_Owner | 所有者| FKCON.OWNER | 1

ForeignKeys | Foreign_Key_Table_Name | テーブル名| FKCON.TABLE_NAME | 2

ForeignKeys | Foreign_Key_Constraint_Name | CONSTRAINTNAME | FKCON.CONSTRAINT_NAME | 3

ForeignKeyColumns | 所有者| 所有者| FKCOLS.OWNER | 1

ForeignKeyColumns | Table_Name | テーブル名| FKCOLS.TABLE_NAME | 2

ForeignKeyColumns | Constraint_Name | CONSTRAINTNAME | FKCOLS.CONSTRAINT_NAME | 3

于 2015-06-04T14:41:50.680 に答える