I have noticed that when I insert with EF, it performs a select to find the next PK.
I have a PK field with Identity set and auto-increment enabled.
Here is the Query
SELECT [ackId]
FROM [dbo].[Acks]
WHERE @@ROWCOUNT > 0 AND [ackId] = scope_identity()
I happened to notice it as it was at the top of the Recent Expensive Queries List in SQL Manger Studio. It doesn't quite make sense that the query to find the PK is more expensive than the actual insert?
Is this normal behaviour? Or is this behaviour causef by entity framework?
Another issue I can think of. If EF is doing a select to get the value, what happens if there are several connections writing to the db? Can there not be a case when the select returns the same value?
Yes it's a normal behavior, when inserting a new entity with identity key.
which is a default convention for numeric and guid
EF will update the temporary key with the inserted key by selecting the last identity value.
And selecting an
scope_identity
will return the last identity value of the inserted entity which will be a new increment value.If you don't want to select the identity value every time you insert a new entity, you can disable the identity option or using fluent api.
And If you insert a lot of records and don't want EF to reselect the identity key you can write a normal ADO.NET sql query or you can also try using
Bulk Insert
.This is a common pattern found in every ORM that supports database-generated identity keys. Identity is a key concept of entities. For example, two clients with the same name are still two distinct clients. A surrogate key like
ClientId
is the only way to tell them apart.An ORM needs to know this surrogate key value in the database and the only way to get it unambiguously when inserting data is by querying
scope_identity()
directly.This never causes race conditions, because an identity column is always incremented when an insert happens (it never rolls back) and
scope_identity()
always returns the identity value that's generated within the scope of theINSERT
statement.The only way to get rid of this expensive pattern is to generate key values in code and set the primary key property to
DatabaseGeneratedOption.None
. But generating and inserting unique primary key values without concurrency problems is not trivial.I guess it's something you have to live with. ORMs were never meant to do bulk inserts, there are other ways to do these.