[轉].Net中刪除數據前進行外鍵衝突檢測

在編寫數據庫系統中爲了保證系統中數據的一致性最簡便且安全的方法就是在DBMS中建立外鍵約束,但刪除主鍵數據時如果違反了外鍵約束,儘管DBMS會給出錯誤提示,如SQL Server的提示信息“%1! 語句與 %2! %3! 約束 '%4!' 衝突。該衝突發生於數據庫 '%6!',表 '%8!'%10!%11!%13!。”,但這些提示信息對最終用戶來說,是不友好的,於是就自己寫了個類,用來刪除記錄時的進行外鍵衝突檢測,代碼如下:

using System;
using System.Data;
using System.Data.SqlClient;
using Microsoft.ApplicationBlocks.Data;

namespace DataAccess.SQLServerDAL
{
///
/// Check 的摘要說明。
///
public class Check
{
///
/// DBMS中保存系統表的
///
const string DEFAULT_SYSTABLES = "systables";

#region CkeckFKBeginDelete

///
/// 在刪除記錄之前先檢測有無外鍵衝突
///
/// 事物對象
/// 要執行刪除操作的表名
/// 要刪除的記錄的主鍵值
/// 返回錯誤信息
/// true - 無衝突,false - 有衝突
public bool CkeckFKBeginDelete(SqlTransaction trans, string tableName, string id, ref string errText)
{
string selectString; //SQL查詢語句
string fkTableName; //外鍵表名稱
string fkColumnName; //外鍵列名稱
object obj; //執行SQL查詢返回值
string description; //外鍵表含義

int count; //外鍵表中引用了主鍵的記錄數

string[] tableNames = {"sysforeignkeys"};

DataSet ds = BuildDataTables();

//檢索所有此表的外鍵表
selectString = "SELECT fkeyid, fkey FROM sysforeignkeys a, sysobjects b WHERE a.rkeyid = b.id AND b.name = @name";

SqlParameter name = new SqlParameter("@name", SqlDbType.VarChar);
name.Value = tableName;

SqlHelper.FillDataset(trans, CommandType.Text, selectString, ds, tableNames, name);

//外鍵表Id
SqlParameter Id = new SqlParameter("@id", SqlDbType.Int);
//外鍵列Id
SqlParameter colid = new SqlParameter("@colid", SqlDbType.Int);
//主鍵值
SqlParameter keyid = new SqlParameter("@keyid", SqlDbType.Int);

//遍歷所有的外鍵表
foreach (DataRow dr in ds.Tables["sysforeignkeys"].Rows)
{
//查詢外鍵表名稱
selectString = "SELECT name FROM sysobjects WHERE id = @id";
Id.Value = dr["fkeyid"];
fkTableName = SqlHelper.ExecuteScalar(trans, CommandType.Text, selectString, Id).ToString();

//查詢外鍵列名稱
selectString = "SELECT name FROM syscolumns WHERE id = @id AND colid = @colid";
Id.Value = dr["fkeyid"];
colid.Value = dr["fkey"];
fkColumnName = SqlHelper.ExecuteScalar(trans, CommandType.Text, selectString, Id, colid).ToString();

//查詢外鍵表中有沒有引用要刪除的主鍵
selectString = "SELECT COUNT(*) FROM " + fkTableName + " WHERE " + fkColumnName + " = @keyid";
keyid.Value = id;
count = Convert.ToInt32(SqlHelper.ExecuteScalar(trans, CommandType.Text, selectString, keyid));

if (count > 0)
{
//查詢發生衝突的表的含義,從而給用戶發出友好的提示
selectString = "SELECT description FROM callCenterTables WHERE tableName = @tableName";
SqlParameter TableName = new SqlParameter("@tableName", SqlDbType.VarChar);
TableName.Value = fkTableName;

obj = SqlHelper.ExecuteScalar(trans, CommandType.Text, selectString, TableName);

if (obj != null)
description = obj.ToString();
else
description = fkTableName;

errText = "您要刪除的數據已在" + description + "中使用,要刪除該條數據,請先刪除" +
description + "中的相關數據,否則您將無法刪除此條記錄!";

return false;
}
}

return true;
}

#endregion

#region BuildDataTables

///
/// 創建外鍵DataTable
///
/// DataSet實例
private DataSet BuildDataTables()
{
DataSet ds = new DataSet();

DataTable table;
DataColumnCollection columns;

table = new DataTable("sysforeignkeys");
columns = table.Columns;

columns.Add("fkeyid", typeof(System.Int32));
columns.Add("fkey", typeof(System.Int32));
ds.Tables.Add(table);

return ds;
}

#endregion
}
}

使用該類時需要在DBMS中建一張系統表,並維護表中的數據,該表用來記錄系統中各用戶表的大概含義,用來告訴用戶是什麼地方發生了衝突:

create table sysTables
(
id int not null IDENTITY(1,1) PRIMARY KEY CLUSTERED, /*ID*/
tableName varchar(255), /*用戶表名稱*/
description varchar(255) /*用戶表描述*/
)

調用示例:

public bool test()
{
//數據庫連接字符串
string connectionString = "";

using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
using (SqlTransaction trans = conn.BeginTransaction())
{
try
{
string execSqlString = "DELETE FROM Test WHERE id = 1";
string errText = "";

if (!new Check().CkeckFKBeginDelete(trans, "test", 1, ref errText))
{
trans.Rollback();
return false;
}

SqlHelper.ExecuteNonQuery(trans, CommandType.Text, execSqlString);
trans.Commit();
return true;
}
catch
{
trans.Rollback();
throw;
}
}
}
}

代碼中用到ms的SqlHelper類,可以到http://msdn.microsoft.com/library/en-us/dnbda/html/daab-rm.asp下載。目前該類僅適用於SQL Server數據庫

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章