Ruby on Rails新增记录时如何避免生成OUTPUT INSERTED语句?
我在Ruby on Rails应用中使用ActiveRecord执行以下代码保存新记录:
Attachment.create({IdAttachment: id , Name: name, Size: params[:file].size, UploadDate: DateTime.now })
但由于该表包含触发器,触发了如下错误:
ActiveRecord::StatementInvalid (TinyTds::Error: The target table 'Attachment' of the DML statement cannot have any enabled triggers if the statement contains an OUTPUT clause without INTO clause.):
查看ActiveRecord自动生成的SQL,发现其中包含OUTPUT INSERTED.[IdAttachment]语句,这正是问题的根源:
EXEC sp_executesql N'INSERT INTO [Attachment] ([IdAttachment], [Title], [IdVch], [IdForm], [Name], [Size], [UploadDate], [IdUser]) OUTPUT INSERTED.[IdAttachment] VALUES (@0, @1, @2, @3, @4, @5, @6, @7)', N'@0 int, @1 nvarchar(max), @2 int, @3 int, @4 nvarchar(max), @5 float, @6 datetime, @7 int', @0 = 21007, @1 = NULL, @2 = NULL, @3 = NULL, @4 = N'uf21007_pic.jpg', @5 = 87041.0, @6 = '11-20-2022 13:23:20.706', @7 = NULL
解决办法
在模型中禁用返回主键的逻辑
因为你已经手动指定了IdAttachment的值(非数据库自增主键),可以在Attachment模型中添加配置,让ActiveRecord不再生成OUTPUT子句:class Attachment < ApplicationRecord self.returning = false end这个设置会告诉SQL Server适配器,不需要通过OUTPUT子句返回插入后的主键,避免和触发器冲突。
直接执行原生SQL语句
绕过ActiveRecord的查询生成器,自行编写不带OUTPUT的INSERT语句:sql = <<~SQL INSERT INTO [Attachment] ([IdAttachment], [Name], [Size], [UploadDate]) VALUES (?, ?, ?, ?) SQL ActiveRecord::Base.connection.execute(sql, id, name, params[:file].size, DateTime.now)这种方式完全由你控制SQL结构,不会包含多余的OUTPUT子句。
修改触发器(备选)
如果允许修改数据库触发器,可以调整触发器逻辑,使其兼容带OUTPUT子句的INSERT语句。不过这种方式需要数据库权限,且可能影响其他业务,建议优先考虑前两种方案。
内容的提问来源于stack exchange,提问作者Behnam

