2015-11-06 51 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关系。