Khi tôi chèn vào các bảng sử dụng thay vì gây nên, @@Identity
, IDENT_CURRENT('Table')
và SCOPE_IDENTITY()
trở lại null. Làm thế nào tôi có thể nhận được danh tính cuối cùng của hàng được chèn?
Khi tôi chèn vào các bảng sử dụng thay vì gây nên, @@Identity
, IDENT_CURRENT('Table')
và SCOPE_IDENTITY()
trở lại null. Làm thế nào tôi có thể nhận được danh tính cuối cùng của hàng được chèn?
Câu trả lời:
Với trình kích hoạt INSTEAD_OF, điều đó có nghĩa là chưa có thao tác chèn nào xảy ra. Bạn không thể biết danh tính vì nó chưa được tạo. Lén lút giá trị từ siêu dữ liệu là có thể ( DBCC CHECKIDENT
) nhưng dựa vào nó sẽ không hoạt động chính xác theo đồng thời và bên cạnh đó nó đòi hỏi các đặc quyền nâng cao.
Các trình kích hoạt INSTEAD_OF rất hiếm khi được yêu cầu và có mùi mã nghiêm trọng. Bạn có chắc bạn cần nó? Bạn không thể thực hiện công việc với trình kích hoạt SAU thường xuyên?
Thay vì kích hoạt, bạn chắc chắn có thể nhận được giá trị được chèn ... nhưng không phải cho đến khi bạn thực hiện thao tác chèn.
USE tempdb;
GO
CREATE TABLE dbo.SmellThis
(
id INT IDENTITY(1,1),
name VARCHAR(32)
);
GO
CREATE TRIGGER dbo.SmellThis_First
ON dbo.SmellThis
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON;
DECLARE @ids TABLE(id INT);
IF NOT EXISTS
(
SELECT 1 FROM sys.objects AS o
INNER JOIN inserted AS i
ON o.name = i.name
)
INSERT dbo.SmellThis(name)
OUTPUT inserted.id INTO @ids
SELECT name
FROM inserted;
SELECT id FROM @ids;
END
GO
INSERT dbo.SmellThis(name) SELECT 'Remus';
GO
Các kết quả:
id
----
1
Bây giờ dọn dẹp:
DROP TABLE dbo.SmellThis;
Như một bên, bạn không bao giờ nên sử dụng @@IDENTITY
hoặc IDENT_CURRENT()
dù thế nào đi nữa. Và SCOPE_IDENTITY
nên được dành riêng cho các tình huống mà bạn chỉ biết có thể chèn một hàng. Một quan niệm sai lầm phổ biến với các trình kích hoạt là chúng bắn mỗi hàng, giống như trong các nền tảng khác, nhưng trong SQL Server, chúng kích hoạt mỗi thao tác - vì vậy, một chèn nhiều hàng sử dụng VALUES(),(),()
hoặc INSERT...SELECT
- SCOPE_IDENTITY
bạn sẽ cài đặt biến nào?
Vấn đề chính: Khung kích hoạt và thực thể đều hoạt động trong phạm vi khác nhau. Vấn đề là, nếu bạn tạo giá trị PK mới trong trình kích hoạt, thì đó là phạm vi khác. Do đó, lệnh này trả về các hàng bằng 0 và EF sẽ ném ngoại lệ.
Giải pháp là thêm câu lệnh CHỌN sau vào cuối Trình kích hoạt của bạn:
SELECT * FROM deleted UNION ALL
SELECT * FROM inserted;
thay cho * bạn có thể đề cập đến tất cả các tên cột bao gồm
SELECT IDENT_CURRENT(‘tablename’) AS <IdentityColumnname>
inserted
có hàng nào được chèn khiINSTEAD OF
kích hoạt kích hoạt.