【问题标题】:Getting the Foreign Key constraints of a table programatically以编程方式获取表的外键约束
【发布时间】:2010-10-30 13:54:01
【问题描述】:

我正在尝试使用 DataTable 来获取 SQL Server DB 的架构。
但是,当尝试检测 ForeignKeys 时,约束集合只会带来 UNIQUE 约束。

Private Sub ShowConstraints(ByVal tableName As String)

    Dim table As DataTable = New DataTable(tableName)
    Using connection As SqlConnection = New SqlConnection(GetConnectionString)

        Dim adapter As SqlDataAdapter = New SqlDataAdapter("Select top 1 * from " + _                  
                                                  tableName, connection)
        connection.Open()
        adapter.FillSchema(table, SchemaType.Mapped)

        For Each c As Constraint In table.Constraints
            If TypeOf c Is ForeignKeyConstraint Then
                Dim fk As ForeignKeyConstraint = CType(c, ForeignKeyConstraint)
                Console.WriteLine("** FK ** relatedTable: {0}; RelatedColumns: {1}", _
                    fk.RelatedTable, fk.RelatedColumns)
            Else
                Console.WriteLine("** Whatever ** Name: {0}; Type: {1}", _
                                           c.ConstraintName, c.GetType.ToString)
            End If
        Next

    End Using


End Sub

如何获得 ForeignKey 约束?

【问题讨论】:

    标签: .net vb.net datatable foreign-keys


    【解决方案1】:

    嗯,这是出乎意料的。事实证明,FillSchema 方法毕竟没有返回外键信息。 我有一些示例代码,看起来应该这样做,但实际上并没有。

    如果您真正想要的是一种编程方式来查询数据库中的所有 FK,那么请从您的代码中尝试这个系统存储过程。

    msdb.dbo.sp_Help 'tableName'

    它返回一个数据集。第 7 个表具有表的所有约束,包括 FK。

    【讨论】:

    • 感谢您的帮助。我最终查询了数据库。这一定是一个错误,你不觉得吗?
    • 不确定是否是错误,但肯定不直观!您肯定会期望 FillSchema() 方法会返回 ForeignKeyConstraints,因为 DataTable 有一个 Constraints Collection。我只能假设出于性能原因它们不会被退回..
    • 在 MSDN 中将 FK 命名为集合中返回的对象...msdn.microsoft.com/en-us/library/…
    【解决方案2】:

    我最终使用了对架构的直接查询。感觉不对,但完成了工作:

    Private Sub ShowFKs()
        Dim sqlstmt As New StringBuilder
    
        sqlstmt.Append(" SELECT ")
        sqlstmt.Append("    rc.CONSTRAINT_NAME,         ")
        sqlstmt.Append("    rcu.TABLE_NAME 'Referencing Table', ")
        sqlstmt.Append("    rcu.COLUMN_NAME 'Referencing Column',")
        sqlstmt.Append("    rcu1.TABLE_NAME 'Referenced Table',")
        sqlstmt.Append("    rcu1.COLUMN_NAME 'Referenced Column'")
        sqlstmt.Append(" FROM")
        sqlstmt.Append("    INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc")
        sqlstmt.Append(" INNER JOIN ")
        sqlstmt.Append("    INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE rcu ")
        sqlstmt.Append("      ON rc.CONSTRAINT_CATALOG = rcu.CONSTRAINT_CATALOG ")
        sqlstmt.Append("         AND rc.CONSTRAINT_NAME = rcu.CONSTRAINT_NAME")
        sqlstmt.Append(" INNER JOIN ")
        sqlstmt.Append("    INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE rcu1 ")
        sqlstmt.Append("      ON rc.UNIQUE_CONSTRAINT_CATALOG = rcu1.CONSTRAINT_CATALOG ")
        sqlstmt.Append("         AND rc.UNIQUE_CONSTRAINT_NAME = rcu1.CONSTRAINT_NAME")
    
        Using connection As SqlConnection = New SqlConnection(GetConnectionString)
            Dim cmd As New SqlCommand(sqlstmt.ToString, connection)
            Dim reader As SqlDataReader
    
            cmd.CommandType = CommandType.Text
    
            connection.Open()
            reader = cmd.ExecuteReader(CommandBehavior.CloseConnection)
    
            Do While reader.Read
                For i As Integer = 0 To reader.FieldCount - 1
                    Console.WriteLine("** {0} = {1}", reader.GetName(i), reader.GetValue(i).ToString)
                Next
                Console.WriteLine("---------------------")
            Loop
        End Using
    
    End Sub
    

    来自这个问题的信息:Query to get all foreign key constraints in SQL Server 2000

    【讨论】:

      【解决方案3】:

      嗯,如果 DataRelations 被禁用或者没有强制执行或级联约束,则可能无法填充 ForeignKeyConstraint 对象。

      这可能会起作用:

          Private Sub ShowConstraints(ByVal tableName As String)
      
          Dim table As DataTable = New DataTable(tableName)
          Using connection As SqlConnection = New SqlConnection(GetConnectionString)
      
              Dim adapter As SqlDataAdapter = New SqlDataAdapter("Select top 1 * from " + _
                                                        tableName, connection)
              connection.Open()
              adapter.FillSchema(table, SchemaType.Mapped)
      
              Console.WriteLine(" ** Parent Relations ** ")
              For Each dr As DataRelation In table.ParentRelations
                  Console.Write("name: {0}: ", dr.RelationName)
                  Dim fk As ForeignKeyConstraint = dr.ChildKeyConstraint
                  If Not (fk Is Nothing) Then
                      Console.WriteLine(" RelatedTable {0}; RelatedColums {1}", _
                          fk.RelatedTable, fk.RelatedColumns)
                  Else
                      Console.WriteLine(" no constraint.")
                  End If
              Next
      
              Console.WriteLine(" ** child Relations ** ")
              For Each dr As DataRelation In table.ChildRelations
                  Console.Write("name: {0}: ", dr.RelationName)
                  Dim fk As ForeignKeyConstraint = dr.ChildKeyConstraint
                  If Not (fk Is Nothing) Then
                      Console.WriteLine(" RelatedTable {0}; RelatedColums {1}", _
                          fk.RelatedTable, fk.RelatedColumns)
                  Else
                      Console.WriteLine(" no constraint.")
                  End If
              Next
          End Using
      
      End Sub
      

      【讨论】:

      • 在相关说明中,仍然不知道什么样的信息应该带来这种“关系”
      【解决方案4】:

      查询 information_schema 表(user_tables / all_tables for oracle) - 它们包含有关您的数据库的元数据。

      【讨论】:

      • 我试图避免这种情况,因为 ADO 中已经有一个 GetSchema 方法
      【解决方案5】:

      最好的方法是直接查询information_schema表:

          SELECT 
            cu.TABLE_SCHEMA + '.' + cu.TABLE_NAME AS TABLE_NAME 
          , cu.COLUMN_NAME 
          , rc.CONSTRAINT_NAME AS FK_NAME 
          , rc.UNIQUE_CONSTRAINT_NAME AS REFERENCE 
         FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE cu INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc 
             ON cu.CONSTRAINT_NAME = rc.CONSTRAINT_NAME 
      

      【讨论】:

      • 这是甲骨文吗?我相信这个问题与 SQL Server 有关。
      • 是的,它是 SQL 服务器。但是我想使用 ADO 去多供应商(开玩笑,这是一个内部项目)
      【解决方案6】:

      这个查询对我有用。

      SELECT rc.[CONSTRAINT_NAME]
        ,fk.[TABLE_NAME]
        ,fk.[COLUMN_NAME]
        ,pk.[TABLE_NAME]
        ,pk.[COLUMN_NAME]
       FROM [LocalV4].[INFORMATION_SCHEMA].[REFERENTIAL_CONSTRAINTS] rc
       inner join [LocalV4].[INFORMATION_SCHEMA].[CONSTRAINT_COLUMN_USAGE] fk on fk.[CONSTRAINT_NAME] = rc.[CONSTRAINT_NAME]
       inner join [LocalV4].[INFORMATION_SCHEMA].[CONSTRAINT_COLUMN_USAGE] pk on pk.[CONSTRAINT_NAME] = rc.[UNIQUE_CONSTRAINT_NAME]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-05-29
        • 2016-08-07
        • 1970-01-01
        • 1970-01-01
        • 2015-06-03
        • 2018-11-25
        • 2021-08-09
        相关资源
        最近更新 更多