Quando si utilizza Entity Framework, utilizza internamente la OUTPUT
tecnica per restituire il valore ID appena inserito
DECLARE @generated_keys table([Id] uniqueidentifier)
INSERT INTO TurboEncabulators(StatorSlots)
OUTPUT inserted.TurboEncabulatorID INTO @generated_keys
VALUES('Malleable logarithmic casing');
SELECT t.[TurboEncabulatorID ]
FROM @generated_keys AS g
JOIN dbo.TurboEncabulators AS t
ON g.Id = t.TurboEncabulatorID
WHERE @@ROWCOUNT > 0
I risultati dell'output vengono archiviati in una variabile di tabella temporanea, riuniti alla tabella e restituiscono il valore della riga dalla tabella.
Nota: non ho idea del motivo per cui EF si unirebbe di nuovo alla tabella effimera alla tabella reale (in quali circostanze i due non corrisponderebbero).
Ma è quello che fa EF.
Questa tecnica ( OUTPUT
) è disponibile solo su SQL Server 2008 o versioni successive.
Modifica : il motivo del join
Il motivo per cui Entity Framework si ricollega alla tabella originale anziché utilizzare semplicemente i OUTPUT
valori è perché EF utilizza anche questa tecnica per ottenere la rowversion
riga appena inserita.
È possibile utilizzare la concorrenza ottimistica nei modelli di framework dell'entità utilizzando l' Timestamp
attributo: 🕗
public class TurboEncabulator
{
public String StatorSlots)
[Timestamp]
public byte[] RowVersion { get; set; }
}
In questo caso, Entity Framework avrà bisogno rowversion
della riga appena inserita:
DECLARE @generated_keys table([Id] uniqueidentifier)
INSERT INTO TurboEncabulators(StatorSlots)
OUTPUT inserted.TurboEncabulatorID INTO @generated_keys
VALUES('Malleable logarithmic casing');
SELECT t.[TurboEncabulatorID], t.[RowVersion]
FROM @generated_keys AS g
JOIN dbo.TurboEncabulators AS t
ON g.Id = t.TurboEncabulatorID
WHERE @@ROWCOUNT > 0
E per recuperarlo Timetsamp
non è possibile utilizzare una OUTPUT
clausola.
Questo perché se c'è un trigger sul tavolo, qualsiasi Timestamp
OUTPUT sarà sbagliato:
- Inserimento iniziale Timestamp: 1
- Timestamp delle uscite della clausola OUTPUT: 1
- il trigger modifica la riga. Timestamp: 2
Il timestamp restituito non sarà mai corretto se si dispone di un trigger sul tavolo. Quindi è necessario utilizzare un separato SELECT
.
E anche se eri disposto a subire una errata rowversion, l'altro motivo per eseguire un separato SELECT
è che non puoi OUTPUT a rowversion
in una variabile di tabella:
DECLARE @generated_keys table([Id] uniqueidentifier, [Rowversion] timestamp)
INSERT INTO TurboEncabulators(StatorSlots)
OUTPUT inserted.TurboEncabulatorID, inserted.Rowversion INTO @generated_keys
VALUES('Malleable logarithmic casing');
Il terzo motivo per farlo è per la simmetria. Quando si esegue un UPDATE
su una tabella con un trigger, non è possibile utilizzare una OUTPUT
clausola. Provare a fare UPDATE
con an OUTPUT
non è supportato e genererà un errore:
L'unico modo per farlo è con una SELECT
dichiarazione di follow-up :
UPDATE TurboEncabulators
SET StatorSlots = 'Lotus-O deltoid type'
WHERE ((TurboEncabulatorID = 1) AND (RowVersion = 792))
SELECT RowVersion
FROM TurboEncabulators
WHERE @@ROWCOUNT > 0 AND TurboEncabulatorID = 1
INSERT INTO Table1(fields...) OUTPUT INSERTED.id VALUES (...)
o metodo precedente:INSERT INTO Table1(fields...) VALUES (...); SELECT SCOPE_IDENTITY();
puoi ottenerlo in c # usando ExecuteScalar ().