C#检测外键冲突的代码

大家都明白,在设计数据库的时候,外键的存在无可避免。在带来好处的同时(确保数据的完整性和一致性等,这些都不多说了),也有它的很多缺陷,那就是使诸如查询等相关操作的效率降低(但有的时候这也是没办法的事情,现在硬件发展都这么快了),但最主要的是,某些时候,在用户不知道各个实体关系的情况下,他们想去删某些记录,下面我们举个例子。

假设有一张产品类别表:Categary,一张产品表Product,其中产品表引用类表表中的类别编号作为外键。

如果出现这样一种情况,一个用户拥有这些表的删除权限,假设他拥有最高权限,也许此时考虑到数据一致性,你不会开放给用户Categary表记录的删除权限,但假设确实有这么种情况,这种产品类别的产品我们以后确实不会在这个系统中使用,也就是某种产品类别的存在没有意义。因此从可维护性的角度来讲,我们需要将这条记录删除是符合业务逻辑需要的。

但如果开放给用户权限吧,用户删除Categary中被Product表中记录引为外键的记录,会出现很多情况:代码不严谨,直接报错抛给用户,很悲剧;严谨点,捕获到异常,但只是告诉用户出错,这是通常的做法,但用户觉得很莫名其妙。如果Categary类别表中确实有垃圾记录,或者用户想删某条记录。我们需要在有外键约束冲突的情况下,给用户更友好的提示信息,或者提醒他,应该先删什么表中的什么数据,然后才能删这条记录等等。

下面是实现:

在项目数据库中增加一张表,该表有数据库管理员维护,此表是项目中其他表之间主外键关系的描述,我们不能直接告诉用户真实的主、外键表(出于安全),但我们可以告诉他们关于这些表功能的描述,让他们知道哪里有冲突,为什么不能删这条记录等等

表名:Sys_PrimaryForeignTables(系统主外键关系表)

字段名

类型

描述

id

Int PK not null

自增编号

primaryTables

Nvarchar(50) not null

主表(如部门表)

foreignTables

Nvarchar(50) not null

引入外键表(如学生表)

foreginId

Nvarchar(20) not null

外键表中的外键字段名

primaryRemark

Nvarchar(255) null

对主表的描述

foreignRemark

Nvarchar(255) null

对引入外键的表的描述

代码的实现:

namespace DTMS.DAL.Components.Common { /// <summary> /// 数据访问层——在删除之前检查是否存在外键约束(辅助类) /// </summary> public static class CheckFKReferences { /// <summary> /// 检查是否存在外键约束 /// </summary> /// <param name="id">要删除记录的主键</param> /// <param name="primaryTable">记录所在的表</param> public static string CheckFKBeforeDelete(string id, string primaryTable) { try { string errText = ""; //连接字符串 string connString = ConfigurationManager.ConnectionStrings["DTMS_DBConnectionString"].ConnectionString; DTMS.DTMS_LINQDataContext db = new DTMS_LINQDataContext(); //取得当前表的所有外键信息 var fts = db.Sys_PrimaryForeignTables.Where(pt => pt.primaryTables.Trim() == primaryTable).ToList(); string fId, fTable, strSQL; string[] sql, sqlArray; int count = 0; for (int i = 0; i < fts.Count; i++) { fId = fts[i].foreginId.Trim(); fTable = fts[i].foreignTables.Trim(); sql = new string[]{ "SELECT COUNT(*) FROM ", fTable, " WHERE ", fId, "='", id, "'" }; strSQL = string.Concat(sql); count = Convert.ToInt32(DTMS.DAL.DBUtility.SqlHelper.ExecuteScalar(connString, System.Data.CommandType.Text, strSQL_1)); if (count > 0) { sqlArray = new string[]{ "在删除[",fts[i].primaryRemark.Trim(),"]中的记录时,由于外键约束,所以该记录暂时无法删除。", "请确保将先[",fts[i].foreignRemark.Trim(),"]中关联的相关记录删除后,再执行此删除操作!"}; errText = string.Concat(sqlArray); LogTools.Instance.Log(errText); return errText; } } return ""; } catch (Exception ex) { throw ex; } } } }

实现很简单,相信你能看得懂,一般情况下,在DAL中,我们在对那些有键作为其他表的外键的表作删除的时候,会先去检查。当然,你也可以为此抽象出一个IDeleteable接口,让每个DAL中有删除操作的业务类去实现这个接口。




原文发布时间为:2010-06-15


本文作者:vinoYang


本文来自云栖社区合作伙伴CSDN博客,了解相关信息可以关注CSDN博客。

上一篇:C# 自定义异常类型(摘自CLR Via C# 3th Edition)


下一篇:面试题:产生一个长度为100的数组,为数组中的每一项随机填充1-100之间的数并且保证不重复