解决DataGridView非连续勾选复选框时仅首个选中行创建触发器问题
问题原因
你当前的代码核心错误是未选中提示和return语句的位置错误,它被放在了foreach遍历循环内部:
- 不管当前遍历的行是否为选中状态,只要第一次循环执行完成,就会直接弹出提示并结束整个方法,后续所有行都不会被遍历
- 你遇到的「连续选中前2行可以生效」属于巧合,大概率是你之前修改代码时缩进错误导致的偶发现象,本质逻辑上只能处理第一行符合条件的数据
修复方案
- 新增选中行计数器,统计所有被勾选的行数量
- 将未选中提示和return逻辑移到
foreach循环外部,只有当计数器为0(没有任何行被勾选)时才触发提示 - 新增CheckBox值空校验,避免空值导致转换报错
- 去掉多余的return逻辑,保证所有选中行都能被遍历处理
修正后的完整代码
public void crear_trigger1() { try { // 新增计数器,统计选中的行数 int checkedRowCount = 0; foreach (DataGridViewRow r_tabla in dataGridView1.Rows) { // 做空值判断,避免CheckBox未赋值时转换报错 bool isChecked = r_tabla.Cells[0].Value != null && Convert.ToBoolean(r_tabla.Cells[0].Value); if (isChecked) { checkedRowCount++; string creacion_tri_in = ""; string creacion_tri_Up = ""; string creacion_tri_eli = ""; string columnas_orig = ""; campos_tablas = new DataTable(); campos_tablas = Traer_informacion("SELECT COL.name AS columna,TYP.name AS Tipo, Longitud = CASE TYP.name WHEN 'nvarchar' THEN COL.LENGTH/2 WHEN 'varchar' THEN COL.LENGTH/2 ELSE COL.LENGTH END FROM dbo.syscolumns COL JOIN dbo.sysobjects OBJ ON OBJ.id = COL.id JOIN dbo.systypes TYP ON TYP.xusertype = COL.xtype LEFT JOIN dbo.sysforeignkeys FK ON FK.fkey = COL.colid AND FK.fkeyid=OBJ.id LEFT JOIN dbo.sysobjects OBJ2 ON OBJ2.id = FK.rkeyid LEFT JOIN dbo.syscolumns COL2 ON COL2.colid = FK.rkey AND COL2.id = OBJ2.id WHERE OBJ.name = '" + r_tabla.Cells[1].Value.ToString() + "' AND (OBJ.xtype='U' OR OBJ.xtype='V') and COL.colstat!=1 group by COL.name ,TYP.name, COL.LENGTH ", set_getcadena_orginen); creacion_tri_in = "CREATE TRIGGER [dbo].[Tr_insertarLog_" + r_tabla.Cells[1].Value.ToString() + "] On [" + set_getbase_orginen + "].[dbo].[" + r_tabla.Cells[1].Value.ToString() + "] AFTER insert AS DECLARE @ipPC VARCHAR(50) SET @ipPC = (SELECT client_net_address FROM sys.dm_exec_connections WHERE session_id = @@spid group by client_net_address) SET ANSI_WARNINGS OFF;"; creacion_tri_Up = "CREATE TRIGGER [dbo].[Tr_ActualizarLog_" + r_tabla.Cells[1].Value.ToString() + "] On [" + set_getbase_orginen + "].[dbo].[" + r_tabla.Cells[1].Value.ToString() + "] AFTER update AS DECLARE @ipPC VARCHAR(50) SET @ipPC = (SELECT client_net_address FROM sys.dm_exec_connections WHERE session_id = @@spid group by client_net_address) SET ANSI_WARNINGS OFF; "; creacion_tri_eli = "CREATE TRIGGER [dbo].[Tr_EliminarLog_" + r_tabla.Cells[1].Value.ToString() + "] On [" + set_getbase_orginen + "].[dbo].[" + r_tabla.Cells[1].Value.ToString() + "] AFTER delete AS DECLARE @ipPC VARCHAR(50) SET @ipPC = (SELECT client_net_address FROM sys.dm_exec_connections WHERE session_id = @@spid group by client_net_address) SET ANSI_WARNINGS OFF;"; for (int j = 0; j < campos_tablas.Rows.Count; j++) { if (j == campos_tablas.Rows.Count - 1) { columnas_orig += "" + campos_tablas.Rows[j]["columna"].ToString() + " "; } else if (j < campos_tablas.Rows.Count - 1) { columnas_orig += "" + campos_tablas.Rows[j]["columna"].ToString() + ","; } } //TRIGGER INSERT creacion_tri_in += "insert into " + set_getbase_destino + ".[dbo].[" + r_tabla.Cells[1].Value.ToString() + "] (" + columnas_orig + " ,[TRANSACCION1], [FECHATRANSACCION1] , [USUARIOTRANSACCION1] , [ipPC1] ,C_ejecutada,Puesto_T) (select top 1 " + columnas_orig + ", 'INSERCION' AS transaccion,getdate() as FECHATRANSACCION,SUSER_SNAME() as USUARIOTRANSACCION ,@ipPC ,(SELECT details.text FROM sys.dm_exec_requests requests CROSS APPLY sys.dm_exec_sql_text (requests.plan_handle) details WHERE requests.session_id > 50) ,HOST_NAME() as esta FROM INSERTED ) SET ANSI_WARNINGS ON; "; Ejectar_consultas(creacion_tri_in, set_getcadena_orginen); //TRIGGER UPDATE creacion_tri_Up += "insert into " + set_getbase_destino + ".[dbo].[" + r_tabla.Cells[1].Value.ToString() + "] (" + columnas_orig + " ,[TRANSACCION1] , [FECHATRANSACCION1] , [USUARIOTRANSACCION1] , [ipPC1],C_ejecutada ,Puesto_T) (select top 1 " + columnas_orig + ", 'ACTUALLIZACION' AS transaccion,getdate() as FECHATRANSACCION,SUSER_SNAME() as USUARIOTRANSACCION ,@ipPC ,(SELECT details.text FROM sys.dm_exec_requests requests CROSS APPLY sys.dm_exec_sql_text (requests.plan_handle) details WHERE requests.session_id > 50 ),HOST_NAME() as esta FROM INSERTED )SET ANSI_WARNINGS ON;"; Ejectar_consultas(creacion_tri_Up, set_getcadena_orginen); //TRIGGER DELETE creacion_tri_eli += "insert into " + set_getbase_destino + ".[dbo].[" + r_tabla.Cells[1].Value.ToString() + "] (" + columnas_orig + ",[TRANSACCION1] , [FECHATRANSACCION1] , [USUARIOTRANSACCION1] , [ipPC1],C_ejecutada,Puesto_T ) (select top 1 " + columnas_orig + ", 'ELIMINACION' AS transaccion,getdate() as FECHATRANSACCION,SUSER_SNAME() as USUARIOTRANSACCION ,@ipPC ,(SELECT details.text FROM sys.dm_exec_requests requests CROSS APPLY sys.dm_exec_sql_text (requests.plan_handle) details WHERE requests.session_id > 50 ) ,HOST_NAME() as esta FROM DELETED)SET ANSI_WARNINGS ON; "; Ejectar_consultas(creacion_tri_eli, set_getcadena_orginen); } } // 遍历完所有行之后再判断是否有选中的行 if (checkedRowCount == 0) { MessageBox.Show("You must select the rows"); return; } // 可选:加成功提示 MessageBox.Show($"已为{checkedRowCount}张表成功创建触发器"); } catch (Exception ex) { set_geterror = ex.Message; return; } }
额外优化建议
- 建议对拼接SQL的表名参数做校验,避免拼写错误或SQL注入风险
- 可以新增触发器存在性判断,创建前先删除已存在的同名触发器,避免重复创建报错
内容的提问来源于stack exchange,提问作者Esteban Giraldo
相关产品推荐
相关产品推荐

