.Net中删除数据前进行外键冲突检测
在编写数据库系统中为了保证系统中数据的一致性最简便且安全的方法就是在DBMS中建立外键约束,但删除主键数据时如果违反了外键约束,尽管DBMS会给出错误提示,如SQL Server的提示信息“%1! 语句与 %2! %3! 约束 '%4!' 冲突。该冲突发生于数据库 '%6!',表 '%8!'%10!%11!%13!。”,但这些提示信息对最终用户来说,是不友好的,于是就自己写了个类,用来删除记录时的进行外键冲突检测,代码如下:
  1![]() using System;
using System;
2![]() using System.Data;
using System.Data;
3![]() using System.Data.SqlClient;
using System.Data.SqlClient;
4![]() using Microsoft.ApplicationBlocks.Data;
using Microsoft.ApplicationBlocks.Data;
5![]()
6![]() namespace DataAccess.SQLServerDAL
namespace DataAccess.SQLServerDAL
7![]() {
{ 
8![]() ///
    ///  
9![]() /// Check 的摘要说明。
    /// Check 的摘要说明。 
10![]() ///
    /// 
11![]() ///
    ///  
12![]() public class Check
    public class Check 
13![]() {
    { 
14![]() ///
        ///   
15![]() /// DBMS中保存系统表的
        /// DBMS中保存系统表的  
16![]() ///
        ///   
17![]() const string DEFAULT_SYSTABLES = "systables";
        const string DEFAULT_SYSTABLES = "systables";
18![]() #region CkeckFKBeginDelete
        #region CkeckFKBeginDelete
19![]() ///
        ///   
20![]() /// 在删除记录之前先检测有无外键冲突
        /// 在删除记录之前先检测有无外键冲突  
21![]() ///
        ///
22![]() /// 事物对象
        /// 事物对象  
23![]() ///
        /// 
24![]() /// 要执行删除操作的表名
        /// 要执行删除操作的表名  
25![]() ///
        /// 
26![]() /// 要删除的记录的主键值
        /// 要删除的记录的主键值  
27![]() ///
        /// 
28![]() /// 返回错误信息
        /// 返回错误信息 
29![]() ///
        /// 
30![]() /// true - 无冲突,false - 有冲突
        /// true - 无冲突,false - 有冲突  
31![]() public bool CkeckFKBeginDelete(SqlTransaction trans, string tableName, string id, ref string errText)
        public bool CkeckFKBeginDelete(SqlTransaction trans, string tableName, string id, ref string errText)  
32![]() {
        {   
33![]() string selectString;
            string selectString; 
34![]() //SQL查询语句
            //SQL查询语句   
35![]() string fkTableName;
            string fkTableName;  
36![]() //外键表名称
            //外键表名称   
37![]() string fkColumnName;
            string fkColumnName; 
38![]() //外键列名称
            //外键列名称   
39![]() object obj;
            object obj;    
40![]() //执行SQL查询返回值
            //执行SQL查询返回值   
41![]() string description;
            string description;  
42![]() //外键表含义
            //外键表含义
43![]() int count;    //外键表中引用了主键的记录数
            int count;    //外键表中引用了主键的记录数
44![]() string[] tableNames = {"sysforeignkeys"};
            string[] tableNames = {"sysforeignkeys"};
45![]() DataSet ds = BuildDataTables();
            DataSet ds = BuildDataTables();
46![]() //检索所有此表的外键表
            //检索所有此表的外键表   
47![]() selectString = "SELECT fkeyid, fkey FROM sysforeignkeys a, sysobjects b WHERE a.rkeyid = b.id AND b.name = @name";
            selectString = "SELECT fkeyid, fkey FROM sysforeignkeys a, sysobjects b WHERE a.rkeyid = b.id AND b.name = @name";
48![]() SqlParameter name = new SqlParameter("@name", SqlDbType.VarChar);   name.Value = tableName;
            SqlParameter name = new SqlParameter("@name", SqlDbType.VarChar);   name.Value = tableName;
49![]() SqlHelper.FillDataset(trans, CommandType.Text, selectString, ds, tableNames, name);
            SqlHelper.FillDataset(trans, CommandType.Text, selectString, ds, tableNames, name);
50![]() //外键表Id
            //外键表Id   
51![]() SqlParameter Id = new SqlParameter("@id", SqlDbType.Int);   //外键列Id
            SqlParameter Id = new SqlParameter("@id", SqlDbType.Int);   //外键列Id   
52![]() SqlParameter colid = new SqlParameter("@colid", SqlDbType.Int);   //主键值
            SqlParameter colid = new SqlParameter("@colid", SqlDbType.Int);   //主键值   
53![]() SqlParameter keyid = new SqlParameter("@keyid", SqlDbType.Int);      //遍历所有的外键表
            SqlParameter keyid = new SqlParameter("@keyid", SqlDbType.Int);      //遍历所有的外键表   
54![]() foreach (DataRow dr in ds.Tables["sysforeignkeys"].Rows)
            foreach (DataRow dr in ds.Tables["sysforeignkeys"].Rows)   
55![]() {    //查询外键表名称
            {    //查询外键表名称    
56![]() selectString = "SELECT name FROM sysobjects WHERE id = @id";
                selectString = "SELECT name FROM sysobjects WHERE id = @id";    
57![]() Id.Value = dr["fkeyid"];
                Id.Value = dr["fkeyid"];    
58![]() fkTableName = SqlHelper.ExecuteScalar(trans, CommandType.Text, selectString, Id).ToString();
                fkTableName = SqlHelper.ExecuteScalar(trans, CommandType.Text, selectString, Id).ToString();       
59![]() //查询外键列名称
                //查询外键列名称   
60![]() selectString = "SELECT name FROM syscolumns WHERE id = @id AND colid = @colid";
                selectString = "SELECT name FROM syscolumns WHERE id = @id AND colid = @colid";    
61![]() Id.Value = dr["fkeyid"];
                Id.Value = dr["fkeyid"];    
62![]() colid.Value = dr["fkey"];
                colid.Value = dr["fkey"];    
63![]() fkColumnName = SqlHelper.ExecuteScalar(trans, CommandType.Text, selectString, Id, colid).ToString();
                fkColumnName = SqlHelper.ExecuteScalar(trans, CommandType.Text, selectString, Id, colid).ToString();
64![]() //查询外键表中有没有引用要删除的主键    selectString = "SELECT COUNT(*) FROM " + fkTableName + " WHERE " + fkColumnName + " = @keyid";
                //查询外键表中有没有引用要删除的主键    selectString = "SELECT COUNT(*) FROM " + fkTableName + " WHERE " + fkColumnName + " = @keyid";    
65![]() keyid.Value = id;
                keyid.Value = id;    
66![]() count = Convert.ToInt32(SqlHelper.ExecuteScalar(trans, CommandType.Text, selectString, keyid));
                count = Convert.ToInt32(SqlHelper.ExecuteScalar(trans, CommandType.Text, selectString, keyid));
67![]() 
    
68![]() if (count > 0)
                if (count > 0)    
69![]() {
                {    
70![]() //查询发生冲突的表的含义,从而给用户发出友好的提示
                    //查询发生冲突的表的含义,从而给用户发出友好的提示     
71![]() selectString = "SELECT description FROM callCenterTables WHERE tableName = @tableName";
                    selectString = "SELECT description FROM callCenterTables WHERE tableName = @tableName";     
72![]() SqlParameter TableName = new SqlParameter("@tableName", SqlDbType.VarChar);
                    SqlParameter TableName = new SqlParameter("@tableName", SqlDbType.VarChar);     
73![]() TableName.Value = fkTableName;
                    TableName.Value = fkTableName;
74![]() obj = SqlHelper.ExecuteScalar(trans, CommandType.Text, selectString, TableName);
                    obj = SqlHelper.ExecuteScalar(trans, CommandType.Text, selectString, TableName);
75![]() if (obj != null)
                    if (obj != null)      
76![]() description = obj.ToString();
                        description = obj.ToString();     
77![]() else
                    else      
78![]() description = fkTableName;
                        description = fkTableName;
79![]() errText = "您要删除的数据已在" + description + "中使用,要删除该条数据,请先删除" +      description + "中的相关数据,否则您将无法删除此条记录!";
                    errText = "您要删除的数据已在" + description + "中使用,要删除该条数据,请先删除" +      description + "中的相关数据,否则您将无法删除此条记录!";
80![]() return false;    }
                    return false;    }   
81![]() }
            }
82![]() return true;  }
            return true;  }
83![]() #endregion
        #endregion
84![]() #region BuildDataTables
        #region BuildDataTables   
85![]() ///
        ///   
86![]() /// 创建外键DataTable
        /// 创建外键DataTable  
87![]() ///
        /// 
88![]() /// DataSet实例
        /// DataSet实例 
89![]() private DataSet BuildDataTables()
        private DataSet BuildDataTables()  
90![]() {
        {
91![]() DataSet ds = new DataSet();
                DataSet ds = new DataSet();      
92![]() DataTable table;
            DataTable table;   
93![]() DataColumnCollection columns;
            DataColumnCollection columns;
94![]() table   = new DataTable("sysforeignkeys");
            table   = new DataTable("sysforeignkeys");   
95![]() columns = table.Columns;
            columns = table.Columns;
96![]() columns.Add("fkeyid", typeof(System.Int32));
            columns.Add("fkeyid", typeof(System.Int32));   
97![]() columns.Add("fkey", typeof(System.Int32));
            columns.Add("fkey", typeof(System.Int32));   
98![]() ds.Tables.Add(table);
            ds.Tables.Add(table);
99![]() return ds;  }
            return ds;  }
100![]() #endregion
        #endregion 
101![]() }
    }
102![]() }
}
103![]()
 using System;
using System;2
 using System.Data;
using System.Data;3
 using System.Data.SqlClient;
using System.Data.SqlClient;4
 using Microsoft.ApplicationBlocks.Data;
using Microsoft.ApplicationBlocks.Data;5

6
 namespace DataAccess.SQLServerDAL
namespace DataAccess.SQLServerDAL7
 {
{ 8
 ///
    ///  9
 /// Check 的摘要说明。
    /// Check 的摘要说明。 10
 ///
    /// 11
 ///
    ///  12
 public class Check
    public class Check 13
 {
    { 14
 ///
        ///   15
 /// DBMS中保存系统表的
        /// DBMS中保存系统表的  16
 ///
        ///   17
 const string DEFAULT_SYSTABLES = "systables";
        const string DEFAULT_SYSTABLES = "systables";18
 #region CkeckFKBeginDelete
        #region CkeckFKBeginDelete19
 ///
        ///   20
 /// 在删除记录之前先检测有无外键冲突
        /// 在删除记录之前先检测有无外键冲突  21
 ///
        ///22
 /// 事物对象
        /// 事物对象  23
 ///
        /// 24
 /// 要执行删除操作的表名
        /// 要执行删除操作的表名  25
 ///
        /// 26
 /// 要删除的记录的主键值
        /// 要删除的记录的主键值  27
 ///
        /// 28
 /// 返回错误信息
        /// 返回错误信息 29
 ///
        /// 30
 /// true - 无冲突,false - 有冲突
        /// true - 无冲突,false - 有冲突  31
 public bool CkeckFKBeginDelete(SqlTransaction trans, string tableName, string id, ref string errText)
        public bool CkeckFKBeginDelete(SqlTransaction trans, string tableName, string id, ref string errText)  32
 {
        {   33
 string selectString;
            string selectString; 34
 //SQL查询语句
            //SQL查询语句   35
 string fkTableName;
            string fkTableName;  36
 //外键表名称
            //外键表名称   37
 string fkColumnName;
            string fkColumnName; 38
 //外键列名称
            //外键列名称   39
 object obj;
            object obj;    40
 //执行SQL查询返回值
            //执行SQL查询返回值   41
 string description;
            string description;  42
 //外键表含义
            //外键表含义43
 int count;    //外键表中引用了主键的记录数
            int count;    //外键表中引用了主键的记录数44
 string[] tableNames = {"sysforeignkeys"};
            string[] tableNames = {"sysforeignkeys"};45
 DataSet ds = BuildDataTables();
            DataSet ds = BuildDataTables();46
 //检索所有此表的外键表
            //检索所有此表的外键表   47
 selectString = "SELECT fkeyid, fkey FROM sysforeignkeys a, sysobjects b WHERE a.rkeyid = b.id AND b.name = @name";
            selectString = "SELECT fkeyid, fkey FROM sysforeignkeys a, sysobjects b WHERE a.rkeyid = b.id AND b.name = @name";48
 SqlParameter name = new SqlParameter("@name", SqlDbType.VarChar);   name.Value = tableName;
            SqlParameter name = new SqlParameter("@name", SqlDbType.VarChar);   name.Value = tableName;49
 SqlHelper.FillDataset(trans, CommandType.Text, selectString, ds, tableNames, name);
            SqlHelper.FillDataset(trans, CommandType.Text, selectString, ds, tableNames, name);50
 //外键表Id
            //外键表Id   51
 SqlParameter Id = new SqlParameter("@id", SqlDbType.Int);   //外键列Id
            SqlParameter Id = new SqlParameter("@id", SqlDbType.Int);   //外键列Id   52
 SqlParameter colid = new SqlParameter("@colid", SqlDbType.Int);   //主键值
            SqlParameter colid = new SqlParameter("@colid", SqlDbType.Int);   //主键值   53
 SqlParameter keyid = new SqlParameter("@keyid", SqlDbType.Int);      //遍历所有的外键表
            SqlParameter keyid = new SqlParameter("@keyid", SqlDbType.Int);      //遍历所有的外键表   54
 foreach (DataRow dr in ds.Tables["sysforeignkeys"].Rows)
            foreach (DataRow dr in ds.Tables["sysforeignkeys"].Rows)   55
 {    //查询外键表名称
            {    //查询外键表名称    56
 selectString = "SELECT name FROM sysobjects WHERE id = @id";
                selectString = "SELECT name FROM sysobjects WHERE id = @id";    57
 Id.Value = dr["fkeyid"];
                Id.Value = dr["fkeyid"];    58
 fkTableName = SqlHelper.ExecuteScalar(trans, CommandType.Text, selectString, Id).ToString();
                fkTableName = SqlHelper.ExecuteScalar(trans, CommandType.Text, selectString, Id).ToString();       59
 //查询外键列名称
                //查询外键列名称   60
 selectString = "SELECT name FROM syscolumns WHERE id = @id AND colid = @colid";
                selectString = "SELECT name FROM syscolumns WHERE id = @id AND colid = @colid";    61
 Id.Value = dr["fkeyid"];
                Id.Value = dr["fkeyid"];    62
 colid.Value = dr["fkey"];
                colid.Value = dr["fkey"];    63
 fkColumnName = SqlHelper.ExecuteScalar(trans, CommandType.Text, selectString, Id, colid).ToString();
                fkColumnName = SqlHelper.ExecuteScalar(trans, CommandType.Text, selectString, Id, colid).ToString();64
 //查询外键表中有没有引用要删除的主键    selectString = "SELECT COUNT(*) FROM " + fkTableName + " WHERE " + fkColumnName + " = @keyid";
                //查询外键表中有没有引用要删除的主键    selectString = "SELECT COUNT(*) FROM " + fkTableName + " WHERE " + fkColumnName + " = @keyid";    65
 keyid.Value = id;
                keyid.Value = id;    66
 count = Convert.ToInt32(SqlHelper.ExecuteScalar(trans, CommandType.Text, selectString, keyid));
                count = Convert.ToInt32(SqlHelper.ExecuteScalar(trans, CommandType.Text, selectString, keyid));67
 
    68
 if (count > 0)
                if (count > 0)    69
 {
                {    70
 //查询发生冲突的表的含义,从而给用户发出友好的提示
                    //查询发生冲突的表的含义,从而给用户发出友好的提示     71
 selectString = "SELECT description FROM callCenterTables WHERE tableName = @tableName";
                    selectString = "SELECT description FROM callCenterTables WHERE tableName = @tableName";     72
 SqlParameter TableName = new SqlParameter("@tableName", SqlDbType.VarChar);
                    SqlParameter TableName = new SqlParameter("@tableName", SqlDbType.VarChar);     73
 TableName.Value = fkTableName;
                    TableName.Value = fkTableName;74
 obj = SqlHelper.ExecuteScalar(trans, CommandType.Text, selectString, TableName);
                    obj = SqlHelper.ExecuteScalar(trans, CommandType.Text, selectString, TableName);75
 if (obj != null)
                    if (obj != null)      76
 description = obj.ToString();
                        description = obj.ToString();     77
 else
                    else      78
 description = fkTableName;
                        description = fkTableName;79
 errText = "您要删除的数据已在" + description + "中使用,要删除该条数据,请先删除" +      description + "中的相关数据,否则您将无法删除此条记录!";
                    errText = "您要删除的数据已在" + description + "中使用,要删除该条数据,请先删除" +      description + "中的相关数据,否则您将无法删除此条记录!";80
 return false;    }
                    return false;    }   81
 }
            }82
 return true;  }
            return true;  }83
 #endregion
        #endregion84
 #region BuildDataTables
        #region BuildDataTables   85
 ///
        ///   86
 /// 创建外键DataTable
        /// 创建外键DataTable  87
 ///
        /// 88
 /// DataSet实例
        /// DataSet实例 89
 private DataSet BuildDataTables()
        private DataSet BuildDataTables()  90
 {
        {91
 DataSet ds = new DataSet();
                DataSet ds = new DataSet();      92
 DataTable table;
            DataTable table;   93
 DataColumnCollection columns;
            DataColumnCollection columns;94
 table   = new DataTable("sysforeignkeys");
            table   = new DataTable("sysforeignkeys");   95
 columns = table.Columns;
            columns = table.Columns;96
 columns.Add("fkeyid", typeof(System.Int32));
            columns.Add("fkeyid", typeof(System.Int32));   97
 columns.Add("fkey", typeof(System.Int32));
            columns.Add("fkey", typeof(System.Int32));   98
 ds.Tables.Add(table);
            ds.Tables.Add(table);99
 return ds;  }
            return ds;  }100
 #endregion
        #endregion 101
 }
    }102
 }
}103

使用该类时需要在DBMS中建一张系统表,并维护表中的数据,该表用来记录系统中各用户表的大概含义,用来告诉用户是什么地方发生了冲突:
create table sysTables(id    int not null IDENTITY(1,1) 
PRIMARY KEY CLUSTERED, /*ID*/
tableName  varchar(255),          /*用户表名称*/
description  varchar(255)          /*用户表描述*/)
调用示例:
 public bool test()
public bool test()   {
        {    //数据库连接字符串   string connectionString = "";
            //数据库连接字符串   string connectionString = ""; using (SqlConnection conn = new SqlConnection(connectionString))
            using (SqlConnection conn = new SqlConnection(connectionString))    {
            { conn.Open();
                conn.Open();     using (SqlTransaction trans = conn.BeginTransaction())
                using (SqlTransaction trans = conn.BeginTransaction())      {
                { try
                    try      {
                    { string execSqlString = "DELETE FROM Test WHERE id = 1";
                        string execSqlString = "DELETE FROM Test WHERE id = 1";       string errText = "";
                        string errText = ""; if (!new Check().CkeckFKBeginDelete(trans, "test", 1, ref errText))
                        if (!new Check().CkeckFKBeginDelete(trans, "test", 1, ref errText))       {
                        {        trans.Rollback();
                            trans.Rollback();        return false;
                            return false;       }
                        } SqlHelper.ExecuteNonQuery(trans, CommandType.Text, execSqlString);
                        SqlHelper.ExecuteNonQuery(trans, CommandType.Text, execSqlString);       trans.Commit();
                        trans.Commit();       return true;
                        return true;      }
                    }      catch
                    catch      {
                    {       trans.Rollback();
                        trans.Rollback();       throw;
                        throw;      }
                    }     }
                }    }
            }   }
        }代码中用到ms的SqlHelper类,可以到http://msdn.microsoft.com/library/en-us/dnbda/html/daab-rm.asp下载。目前该类仅适用于SQL Server数据库
 
                     
                    
                 
                    
                

 
     
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号