使用EF向表中添加新行时发​​生主键约束违规

Mik*_*sen 4 .net c# sql entity-framework entity-framework-4

我们的网络应用程序中出现了一个非常断断续续的(每隔几周有人抱怨这个)主键约束违规.我搜索了代码库,甚至在这个表中创建任何行的代码如下:

decimal nextDocId = (from d in context.TPM_PROJECTVERSIONDOCS
                     orderby d.DOCUMENTID descending
                     select d.DOCUMENTID).Max() + 1;

foreach (TPM_PROJECTVERSIONDOCS doc in documents)
{
   TPM_PROJECTVERSIONDOCS newDoc = new TPM_PROJECTVERSIONDOCS();
   newDoc.DOCUMENTID = nextDocId;
   newDoc.DOCBLOB = doc.DOCBLOB;
   newDoc.DOCUMENTNAME = doc.DOCUMENTNAME;
   newDoc.FILECONTENTTYPE = doc.FILECONTENTTYPE;
   version.TPM_PROJECTVERSIONDOCS.Add(newDoc);
   nextDocId++;
}
Run Code Online (Sandbox Code Playgroud)

我们得到的错误是:

ORA-00001: unique constraint (TPMDBO.TPM_PROJECTVERSIONDOCS_PK) violated
Run Code Online (Sandbox Code Playgroud)

这意味着它DOCUMENTID已经在使用中.关于是什么原因,我有一些理论.首先,如果多个人同时添加文档,在nextDocId设置时间和上下文保存时间之间的某个时间点,可能已将新文档添加到数据库中.但是,这个时间只有几毫秒,所以我认为这不太可能是我们网站获得的少量流量.

我的第二个理论可能是EF做某种缓存,并nextDocId返回一个不再有效的缓存值.

由于这个错误只是经常发生,当然只在我们的生产服务器上,我没有好的方法来调试它或repro.

我的问题:最可能的原因是什么,是否有更好的方法来重写此代码以防止主键违规?我很乐意只为主键使用自动递增字段,但遗憾的是Oracle不支持它们.切换到UUID也是一种解决方案,但会导致很多数据库更改.谢谢!

更新:

这是TPM_PROJECTVERSIONDOCS实体:

<EntityType Name="TPM_PROJECTVERSIONDOCS">
   <Key>
      <PropertyRef Name="DOCUMENTID" />
   </Key>
   <Property Name="DOCUMENTID" Type="decimal" Nullable="false" />
   <Property Name="PROJECTID" Type="decimal" Nullable="false" />
   <Property Name="VERSIONID" Type="decimal" Nullable="false" />
   <Property Name="DOCUMENTNAME" Type="VARCHAR2" Nullable="false" MaxLength="500" />
   <Property Name="DOCBLOB" Type="BLOB" Nullable="false" />
   <Property Name="FILECONTENTTYPE" Type="VARCHAR2" Nullable="false" MaxLength="80" />
</EntityType>
Run Code Online (Sandbox Code Playgroud)

我不知道有任何方法要么DOCUMENTID默认使用序列,要么使用EF查询序列.

小智 6

由于您使用的是Oracle,因此您应该使用oracle序列值.它不会返回重复!调用sequence.nextval而不是max()+ 1将解决它.