2015-11-06 19 views
0

存在國外的依賴出於測試目的截斷表我有需要SqlConnection或連接字符串和字符串的方法。該方法檢查SqlConnectionDbContext.Database.Connection.ConnectionString針對一組「危險」的字符串,如果在連接字符串有任何「危險」的字符串,它不執行其查詢。如何當通過C#

基本上,我需要知道如何執行(通過C#)一截斷/刪除表中的所有數據。然而問題是外國的依賴。我正在嘗試以下方法。刪除所有依賴項,刪除表,然後恢復所有依賴項,但是我遇到了問題,我恢復了所有依賴項代碼。我怎樣才能通過C#做到這一點?

應該刪除該表主要方法。

public int DeleteFromDatabase(SqlConnection sqlConnection, string tableName) 
{ 
     int success = 0; 

     string sqlTrunc = "Delete from " + tableName; 

     if (isSafeSqlConnection(sqlConnection)) 
     { 
      DropAllConstraints(); 

      using (sqlConnection) 
      { 
       SqlCommand cmd = new SqlCommand(sqlTrunc, sqlConnection); 
       sqlConnection.Open(); 
       success = cmd.ExecuteNonQuery(); 
       sqlConnection.Close(); 
      } 

      ReinstateAllConstraints(); //<=error happens here. 
     } 
     return success; 
} 

這滴所有約束:

​​

這就驗證了傳入的連接不是活的服務器:

private bool isSafeSqlConnection(SqlConnection connection) 
{ 
    string pathToUNsafeStrings = @"Utility\UnsafeStrings\UnsafeStrings.txt"; 
    string[] unsafeStrings = File.ReadAllLines(pathToUNsafeStrings); 

    foreach (var item in unsafeStrings) 
    { 
     if (connection.ConnectionString.Contains(item)) 
      return false; 
    } 

    return true; 
} 

該方法主要執行的每個條目從該查詢返回:

select 
    'ALTER TABLE dbo.' + object_name(fk.parent_object_id) + 
    ' ADD CONSTRAINT ' + fk.name + 
    ' FOREIGN KEY(' + c1.name + ') REFERENCES dbo.' + 
    object_name(fk.referenced_object_id) + '(' + c2.name + ')' as col1 
from 
    sys.foreign_keys fk 
inner join 
    sys.foreign_key_columns fkc ON fk.object_id = fkc.constraint_object_id 
inner join 
    sys.columns c1 ON fkc.parent_column_id = c1.column_id and c1.object_id = fkc.parent_object_id 
inner join 
    sys.columns c2 ON fkc.referenced_column_id = c2.column_id and c2.object_id = fkc.referenced_object_id 

public void ReinstateAllConstraints() 
{ 
    string[] reinstateAllConstraints = File.ReadAllLines(@"Utility\UnsafeStrings\reisntateconstraint.txt"); 

    using (var connection = new SqlConnection(connectionString)) 
    { 
     connection.Open(); 

     foreach (var item in reinstateAllConstraints) 
     { 
      var command = new SqlCommand(item, connection); 
      command.ExecuteNonQuery(); 
     } 

     connection.Close(); 
    } 
} 
+0

您刪除的依賴關係,或者你不截斷在別處引用的記錄。不知道這裏有什麼問題。 – Will

+0

@Will我如何確保一旦刪除了依賴關係,所有的依賴關係都會被恢復? –

+0

如果記錄X取決於記錄Y,那麼您只能刪除X和Y或將它們留下。你不能刪除Y並離開X. – Will

回答

1

你可以做到這一點的工作流程:

  1. 禁用外鍵檢查。
  2. 從引用要刪除的表的表中刪除所有寄存器。
  3. 從表格中刪除所有要刪除的寄存器。
  4. 啓用外鍵檢查。

您可以在下面這段代碼見(我使用C#6

public bool TruncateTable(string tableName) 
{ 
    string sqlTrunc = $"Delete from {tableName}"; 

    if (isSafeSqlConnection(sqlConnection)) 
    { 
     DisableAllForeignKeys(); 

     using (sqlConnection) 
     { 
      DeleteAllDependencies(tableName, sqlConnection); 

      SqlCommand cmd = new SqlCommand(sqlTrunc, sqlConnection); 
      sqlConnection.Open(); 
      success = cmd.ExecuteNonQuery(); 
      sqlConnection.Close(); 
     } 

     EnableAllForeignKeys(); 
    } 
    return success; 
} 


public void DisableAllForeignKeys(SqlConnection sqlConnection) 
{ 
    using(var command = new SqlCommand($"EXEC sp_msforeachtable \"ALTER TABLE ? NOCHECK CONSTRAINT all\"", sqlConnection)) 
     command.ExecuteNonQuery(); 
} 

public void EnableAllForeignKeys(SqlConnection sqlConnection) 
{ 
    using(var command = new SqlCommand($"EXEC sp_msforeachtable \"ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all\"", sqlConnection)) 
     command.ExecuteNonQuery(); 
} 

private static void DeleteAllDependencies(string tableName, SqlConnection sqlConnection) 
{ 
    var sql = 
     [email protected]"SELECT t.name AS 'Table that contains FK', 
fk.name AS 'FK Name', 
t1.Name AS 'Table that is being referenced' 
FROM sys.foreign_key_columns fkc 
INNER JOIN sys.tables t ON t.object_id = fkc.parent_object_id 
INNER JOIN sys.tables t1 ON t1.object_id = fkc.referenced_object_id 
INNER JOIN sys.columns c1 ON c1.object_id = fkc.parent_object_id AND c1.column_id = fkc.parent_column_id 
INNER JOIN sys.foreign_keys fk ON fk.object_id = fkc.constraint_object_id 
INNER JOIN sys.schemas sc ON t.schema_id = sc.schema_id 
WHERE (sc.name + '.' +t1.name) = 'dbo.{ 
      tableName}';"; 

    var command = sqlConnection.CreateCommand(); 
    command.CommandText = sql; 

    List<Tuple<string, string, string>> tuples; 
    using (var dataReader = command.ExecuteReader()) 
    { 
     var enumerator = dataReader.GetEnumerator(); 
     tuples = Enumerable.Range(1, int.MaxValue) 
          .TakeWhile(i => enumerator.MoveNext()) 
          .Select(i => (IDataRecord)enumerator.Current) 
          .Select(dr => Tuple.Create(dr.GetString(0), dr.GetString(1), dr.GetString(2))) 
          .ToList(); 
    } 


    foreach (var tuple in tuples) 
    { 
     using (var sqlCommand = sqlConnection.CreateCommand()) 
     { 
      sqlCommand.CommandText = $"DELETE FROM {tuple.Item1}"; 
      sqlCommand.ExecuteNonQuery(); 
     } 
    } 
} 
+0

像我的其他代碼一樣,禁用所有的外部約束正在工作,當它啓用所有外鍵的時候,這將導致SqlException ALTER TABLE語句與FOREIGN KEY約束「FK_BookingRevisionAddOnProductSelections_BookingRevisionId」衝突。衝突發生在數據庫「Dev。DbContext「,表」dbo.BookingRevisions「,'Id'列。 –

+0

@DonnieBrasco我只是改變了我的代碼來解決這個問題 –

1

您可能需要配置關係相應變化傳播(「層疊」),這樣,當一個關係的一部分被刪除,另一個被刪除或更新。

DBMS正確地說,如果您從其他表中引用的項目不存在,則無法激活fk關係。