Cách nhận hàng nhận dạng cuối cùng được chèn khi sử dụng thay vì kích hoạt


8

Khi tôi chèn vào các bảng sử dụng thay vì gây nên, @@Identity, IDENT_CURRENT('Table')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?


Không insertedcó hàng nào được chèn khi INSTEAD OFkích hoạt kích hoạt.
ypercubeᵀᴹ

Kiểm tra câu hỏi SO này: nó có thể giúp đỡ. stackoverflow.com/q/908257/27535
gbn

Bạn phải chọn Chọn Id, .. từ Đã chèn, ở đây Scope_Identity, @@ Danh tính sẽ không hoạt động

Câu trả lời:


8

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?


Tôi muốn kiểm soát tính toàn vẹn dữ liệu của hàng được chèn. trước khi cứu họ. Nếu dữ liệu không tốt, tôi tăng thông báo tỷ lệ lỗi.
mehdi lotfi

2
Bạn đang mô tả một khóa ngoại. Nó phải là trách nhiệm ứng dụng để chèn vào bảng con, không phải là một kích hoạt. Làm điều đó từ một trình kích hoạt là một thiết kế tồi, và dù sao thì nó cũng có thể được thực hiện từ một trình kích hoạt SAU bình thường. Một kích hoạt sau có thể gây ra lỗi và gây ra rollback, đó là tùy chọn tốt hơn so với kích hoạt thay vì kích hoạt.
Remus Rusanu

1
Thật là một khái niệm phi lý - "thay vì kích hoạt là một mùi mã nghiêm trọng"? Chúng rất hữu ích so với trình kích hoạt sau - trong đó, nếu quy tắc kinh doanh của bạn bị vi phạm, bạn đã thực hiện công việc hai lần - bạn đã chèn các hàng và sau đó bạn đã cuộn chúng lại. Thay vì kích hoạt có thể ngăn bất kỳ công việc nào xảy ra nếu quy tắc kinh doanh của bạn không thể được thi hành với DRI bình thường hoặc các ràng buộc khác.
Aaron Bertrand

1
Mặc dù "thay vì kích hoạt là một mùi mã nghiêm trọng", không phải là một quy tắc nghiêm ngặt, nó dựa trên các vấn đề thực tế có thể xảy ra trong một hệ thống hoàn chỉnh. Nói chung, các công cụ phá vỡ quy tắc kinh doanh không bao giờ nên xảy ra trong hệ thống, chứ chưa nói đến việc đạt đến cấp độ cơ sở dữ liệu. Trong trường hợp đó, xác thực quy tắc trong trình kích hoạt chỉ thích hợp làm cơ chế bảo vệ cuối cùng trong trường hợp có lỗ hổng trong hệ thống.
Alireza

4
Tuyên bố toàn vẹn luôn luôn tốt hơn một kích hoạt. Một kích hoạt sau luôn luôn tốt hơn một kích hoạt thay vì kích hoạt. Thay vào đó - trong số các trình kích hoạt có hành vi 'vui nhộn' trong nhiều tình huống, chúng không rõ ràng để truy cập tối ưu hóa đường dẫn trong DML, chúng làm cho các mức cô lập hành xử thất thường. Thay vào đó - kích hoạt tiếng hét 'Thay vào đó tôi nên là một thủ tục lưu trữ truy cập'. Và tôi không mua đối số 'thực hiện công việc hai lần', tối ưu hóa đường dẫn ngoại lệ sẽ không ảnh hưởng đến thiết kế, đặc biệt với chi phí làm chậm đường dẫn thường xuyên .
Remus Rusanu

11

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 @@IDENTITYhoặc IDENT_CURRENT()dù thế nào đi nữa. Và SCOPE_IDENTITYnê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_IDENTITYbạn sẽ cài đặt biến nào?


Làm thế nào tôi lưu kết quả của bản ghi được chèn trong bảng biến để sử dụng sau này.
mehdi lotfi

@mehdi bạn có thể định nghĩa "sau" không? Và bạn có thể thêm các cột vào biến bảng mà tôi đã khai báo ở trên không?
Aaron Bertrand

2
Tôi yêu tên bảng của bạn.
Dan Esparza

-1

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>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.