简体   繁体   English

EF上的InvalidOperationException

[英]InvalidOperationException on EF

I'm using WPF MVVM Pettern and I Have a simple table on SQL Server 2012 which its ID (key) column is computed in an StoredProcedure, called PersonInsert : (This is simplified, but what is computed is more complex than this, anyway it's an int at last) 我正在使用WPF MVVM Pettern,并且在SQL Server 2012上有一个简单的表,该表的ID (键)列是在StoredProcedure中计算的,称为PersonInsert :最后一个int

USE [Guard]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[PersonInsert]
@FName NVARCHAR(50) ,
@LName NVARCHAR(50) ,
@ID INT = NULL OUTPUT
AS
BEGIN
    BEGIN TRY
        SELECT  @ID = ISNULL(MAX(ID), 0) + 1
        FROM    dbo.Person


        INSERT  INTO [dbo].[Person]
                ( [ID] ,
                  [FName] ,
                  [LName] 
                )
        VALUES  ( @ID ,
                  @FName ,
                  @LName 
                )
    END TRY
    BEGIN CATCH
        DECLARE @ErrMsg NVARCHAR(MAX) ,
            @ErrSvr INT ,
            @ErrStt INT

        SELECT  @ErrMsg = ERROR_MESSAGE() + '|' + ERROR_PROCEDURE() + '|'
                + CAST(ERROR_LINE() AS NVARCHAR(5)) ,
                @ErrSvr = ERROR_SEVERITY() ,
                @ErrStt = ERROR_STATE()

        RAISERROR (@ErrMsg, @ErrSvr, @ErrStt)
    END CATCH
END
GO

In the .net side, I use EF 6.1 Code-First to handle data and mapped to SPs so I have OnModelCreating like this: 在.net端,我使用EF 6.1 Code-First来处理数据并映射到SP,因此我具有OnModelCreating

modelBuilder.Entity(Of Person)().MapToStoredProcedures(
                    Sub(x)
                          x.Insert(Function(e) e.HasName("[dbo].[PersonInsert]"))
                          x.Update(Function(e) e.HasName("[dbo].[PersonUpdate]"))
                          x.Delete(Function(e) e.HasName("[dbo].[PersonDelete]"))
                    End Sub)

And My Model is: 我的模型是:

<Table("Person")> _
Partial Public Class Person

    <DatabaseGenerated(DatabaseGeneratedOption.None), Key> _
    Public Property ID As Integer

    Public Property FName As String
    Public Property LName as String
End Class

Now the strange thing is, when I try to Insert Data (Adding New Person) at first time, the db.SaveChanged() works great, but for second time it throws InvalidOperation exception with a message: 现在奇怪的是,当我第一次尝试插入数据(添加新人员)时, db.SaveChanged()工作得很好,但是第二次它抛出InvalidOperation异常并显示一条消息:

The changes to the database were committed successfully , but an error occurred while updating the object context. 成功提交对数据库的更改,但是更新对象上下文时发生错误。 The ObjectContext might be in an inconsistent state. ObjectContext可能处于不一致状态。 Inner exception message: Saving or accepting changes failed because more than one entity of type 'Shoniz.Guard.WPFGuardApplication.Person' have the same primary key value. 内部异常消息:保存或接受更改失败,因为多个“ Shoniz.Guard.WPFGuardApplication.Person”类型的实体具有相同的主键值 Ensure that explicitly set primary key values are unique. 确保显式设置的主键值是唯一的。 Ensure that database-generated primary keys are configured correctly in the database and in the Entity Framework model. 确保在数据库和实体框架模型中正确配置了数据库生成的主键。 Use the Entity Designer for Database First/Model First configuration. 将实体设计器用于数据库优先/模型优先配置。 Use the 'HasDatabaseGeneratedOption" fluent API or ' DatabaseGeneratedAttribute ' for Code First configuration. 使用“ HasDatabaseGeneratedOption”流利的API或“ DatabaseGeneratedAttribute ”进行代码优先配置。

He is right! 他是对的! the data is comitted successfully! 数据成功提交! and I'm right too, because my ID (key) column is computed right and it's completely unique. 我也是对的,因为我的ID (密钥)列是正确计算的,并且是唯一的。 Either I have used the DatabaseGeneratedAttribute with none value on ID, but the result is the same :( 我使用过的DatabaseGeneratedAttribute的 ID 都没有值,但是结果是相同的:(

Even when I re-query the db to check about duplicate keys, I find NOTHING! 即使当我重新查询数据库以检查重复的键时,我也没发现!

  1. Why this exception is thrown? 为什么抛出此异常?
  2. How can I prevent that? 我该如何预防?
  3. Is there anyway to Ignore the changes after db.SaveChanges() ? 无论如何,是否有忽略db.SaveChanges()之后的更改?

First of all change DatabaseGeneratedOption.None to DatabaseGeneratedOption.Indetity and finally change stored procedure to this: 首先将DatabaseGeneratedOption.None更改为DatabaseGeneratedOption.Indetity ,最后将存储过程更改为此:

BEGIN TRY
        SELECT  @ID = ISNULL(MAX(ID), 0) + 1
        FROM    dbo.Person


        INSERT  INTO [dbo].[Person]
                ( [ID] ,
                  [FName] ,
                  [LName] 
                )
        VALUES  ( @ID ,
                  @FName ,
                  @LName 
                )
        --You have to tell EF this is returned Id of inserted person
        SELECT @ID as ID
    END TRY

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM