C# SQL Server:检查子行是否存在
我正在开发一个web应用程序,其中有许多表,但两个表足以说明我的问题: 使用者 顺序 假设User表有一个主键UserID,它是Order表中名为CreatedBy_UserID的外键 在删除用户之前,我想检查订单表是否有即将删除的用户创建的记录 我知道,如果我试图删除该用户,就会发生SqlException,但我想事先检查Order表是否没有该用户创建的任何记录?是否有任何SQL代码,我可以运行它来检查一个表的所有外键,如果该行被引用 这对我来说通常是有用的代码,因为如果可以检测到用户存在于这些其他表中,我可以完全删除删除选项 我不想要一个简单的查询,从Order中选择COUNT*,其中CreatedBy_UserID==@UserID,因为如果我为Order表创建另一个外键,这将不起作用。相反,我想要的东西将遍历所有外键C# SQL Server:检查子行是否存在,c#,sql,sql-server,foreign-keys,C#,Sql,Sql Server,Foreign Keys,我正在开发一个web应用程序,其中有许多表,但两个表足以说明我的问题: 使用者 顺序 假设User表有一个主键UserID,它是Order表中名为CreatedBy_UserID的外键 在删除用户之前,我想检查订单表是否有即将删除的用户创建的记录 我知道,如果我试图删除该用户,就会发生SqlException,但我想事先检查Order表是否没有该用户创建的任何记录?是否有任何SQL代码,我可以运行它来检查一个表的所有外键,如果该行被引用 这对我来说通常是有用的代码,因为如果可以检测到用户存在于这
可以这样做吗?在存在多个FK列的情况下,没有干净的方法来迭代所有FK列。您必须构建一些动态SQL来查询系统表并依次测试每个表 就我个人而言,我不会这么做。我知道我有什么FKs:我将依次测试每个FKs
...
IF EXISTS (SELECT * FROM Order WHERE CreatedBy_UserID == @userID)
RAISERROR ('User created Orders ', 16, 1)
IF EXISTS (SELECT * FROM Order WHERE PackedBy_UserID == @userID)
RAISERROR ('User packed Orders', 16, 1)
...
您不会动态地遍历某个用户对象的每个属性,并对每个属性进行常规测试,是吗?每个属性都有代码下面是我过去执行此任务时使用的sp的代码请原谅缩进:
create proc dbo.usp_ForeignKeyCheck(
@tableName varchar(100),
@columnName varchar(100),
@idValue int
) as begin
set nocount on
declare fksCursor cursor fast_forward for
select tc.table_name, ccu.column_name
from
information_schema.table_constraints tc join
information_schema.constraint_column_usage ccu on tc.constraint_name = ccu.constraint_name join
information_schema.referential_constraints rc on tc.constraint_name = rc.constraint_name join
information_schema.table_constraints tc2 on rc.unique_constraint_name = tc2.constraint_name join
information_schema.constraint_column_usage ccu2 on tc2.constraint_name = ccu2.constraint_name
where tc.constraint_type = 'Foreign Key' and tc2.table_name = @tableName and ccu2.column_name = @columnName
order by tc.table_name
declare
@fkTableName varchar(100),
@fkColumnName varchar(100),
@fkFound bit,
@params nvarchar(100),
@sql nvarchar(500)
open fksCursor
fetch next from fksCursor
into @fkTableName, @fkColumnName
set @fkFound = 0
set @params=N'@fkFound bit output'
while @@fetch_status = 0 and coalesce(@fkFound,0) <> 1 begin
select @sql = 'set @fkFound = (select top 1 1 from [' + @fkTableName + '] where [' + @fkColumnName + '] = ' + cast(@idValue as varchar(10)) + ')'
print @sql
exec sp_executesql @sql,@params,@fkFound output
fetch next from fksCursor
into @fkTableName, @fkColumnName
end
close fksCursor
deallocate fksCursor
select coalesce(@fkFound,0)
return 0
end
此代码将为您提供为指定表定义的外键列表: 从sys.objects中选择不同的名称 其中,在sys.foreign\u key\u列中选择约束\u object\u id作为fk 其中fk.Parent\u object\u id=从sys.tables中选择object\u id
其中name='tablename'您可以使用事务检查它。 我知道它看起来像石头斧头,但它工作得又快又稳
private bool TestUser(string connectionString, int userID)
{
var result = true;
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
var command = connection.CreateCommand();
var transaction = connection.BeginTransaction();
command.Connection = connection;
command.Transaction = transaction;
try
{
command.CommandText = "DELETE User WHERE UserID = " + userID.ToString();
command.ExecuteNonQuery();
transaction.Rollback();
}
catch
{
result = false;
}
}
return result;
}
要使用thisTrue,您应该知道所有具有外键的字段,尽管良好的db设计只能从父表的Id列中使用FK。从其他列中FK不是很好的实践。
private bool TestUser(string connectionString, int userID)
{
var result = true;
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
var command = connection.CreateCommand();
var transaction = connection.BeginTransaction();
command.Connection = connection;
command.Transaction = transaction;
try
{
command.CommandText = "DELETE User WHERE UserID = " + userID.ToString();
command.ExecuteNonQuery();
transaction.Rollback();
}
catch
{
result = false;
}
}
return result;
}