EF performing a select on every insert with Identity column

独自空忆成欢 提交于 2019-11-28 10:51:46

问题


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?


回答1:


Yes it's a normal behavior, when inserting a new entity with identity key.

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]

which is a default convention for numeric and guid

Code First infers that a property is a primary key if a property on a class is named “ID” (not case sensitive), or the class name followed by "ID". If the type of the primary key property is numeric or GUID it will be configured as an identity column. - MSDN

EF will update the temporary key with the inserted key by selecting the last identity value.

The Entity Framework replaces the value of the property in a temporary key with the identity value that is generated by the data source after SaveChanges is called. - MSDN

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.

[DatabaseGenerated(DatabaseGeneratedOption.None)]

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.




回答2:


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 the INSERT 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.



来源:https://stackoverflow.com/questions/25500591/ef-performing-a-select-on-every-insert-with-identity-column

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!