无法在实体框架中更新具有唯一约束索引的实体

Posted

技术标签:

【中文标题】无法在实体框架中更新具有唯一约束索引的实体【英文标题】:Can't update entity with unique constraint index in Entity Framework 【发布时间】:2017-03-20 06:28:28 【问题描述】:

我有一个实体 Invoice,其中有 1 个 Provider 和许多 ParticularFieldValues。在我的发票中,属性 InvoiceNumber 中有一个唯一索引约束。

问题是我想在Invoice 中做最小的更改,它抛出一个异常说我不能SaveChanges 因为重复的唯一索引InvoiceNumber

我也尝试了附加,它说我不能因为相同的重复。

这是我的表格图:

发票类:

public class Invoice

        public int InvoiceId  get; set; 
        public int InvoiceNumber  get; set; 
        public virtual int ProviderId  get; set; 
        public virtual Provider Provider  get; set; 

        public virtual ICollection<ParticularFieldValue> ParticularProviderFieldsToComplete  get; set; 

        public DateTime DueDate  get; set; 

        public int TotalAmount  get; set; 

这是我不能做的操作:

public void UpdatePayment(Invoice inv)

            UnitOfWork.Invoices.Update(inv);
            UnitOfWork.Save();


public void Update(Invoice inv)

            Invoice invDb = base.Get(inv.InvoiceId);
            invDb.TotalAmount = inv.TotalAmount;


public TEntity Get(int id)

            return dbSet.Find(id);

还有例外:

"ExceptionMessage": "更新条目时发生错误。有关详细信息,请参阅内部异常。", “内部异常”: "Message": "发生错误。", "ExceptionMessage": "No se puede insertar una fila de clave duplicada en el objeto 'dbo.Invoices' con índice único 'IX_InvoiceNumber'. El valor de la clave duplicada es (123451).\r\nSe terminó la instrucción.", "ExceptionType": "System.Data.SqlClient.SqlException", “堆栈跟踪”:“ zh System.Data.SqlClient.SqlConnection.OnError(SqlException 异常, 布尔型 breakConnection,Action1 wrapCloseInAction) en System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction) zh System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) zh System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) zh System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() zh System.Data.SqlClient.SqlDataReader.get_MetaData() zh System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption) zh System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior、RunBehavior runBehavior、布尔 returnStream、布尔 异步,Int32 超时,任务和任务,布尔 asyncWrite,布尔 inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest) zh System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior、RunBehavior、runBehavior、布尔返回流、字符串 方法,TaskCompletionSource1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry) en System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) en System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) en System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior) en System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior) en System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.<Reader>b__c(DbCommand t, DbCommandInterceptionContext1 c) en System.Data.Entity.Infrastructure.Interception.InternalDispatcher1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func3 操作,TInterceptionContext 拦截上下文, Action3 executing, Action3 已执行)\r\n en System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.Reader(DbCommand 命令,DbCommandInterceptionContext 拦截上下文)\r\n zh System.Data.Entity.Internal.InterceptableDbCommand.ExecuteDbDataReader(CommandBehavior 行为)\r\n zh System.Data.Common.DbCommand.ExecuteReader(CommandBehavior 行为)\r\n zh System.Data.Entity.Core.Mapping.Update.Internal.DynamicUpdateCommand.Execute(Dictionary2 identifierValues, List1 generatedValues)\r\n en System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.Update()

【问题讨论】:

检查您现有的所有发票,确保唯一索引约束InvoiceNumber 是自动递增的,或者如果您手动设置它,请确保您设置的是表中不存在的. 问题是我想用相同的 InvoiceNumber 更新发票 调用Get(int id)时出现什么错误? 检查 EntityState。如果要修改,则必须修改该实体的 EntityState。在您的情况下,它可能已添加。由于唯一键约束,不允许添加重复。 【参考方案1】:

遇到同样的问题,原来是在更新实体之前,我先尝试添加,如果记录已经存在,那么在某些情况下我更改了该记录。并且在添加的时候,当弹出记录已经存在的错误时,忘记及时调用这个实体上的Detach,所以当我后来尝试更新我的属性时,DbContext尝试做的第一件事就是添加一个db 中已经存在的实体(因此,导致了有关唯一索引的错误),但它从未达到更新的地步。简而言之,检查你是否召唤了从任何地方的实体分离。

【讨论】:

以上是关于无法在实体框架中更新具有唯一约束索引的实体的主要内容,如果未能解决你的问题,请参考以下文章

实体框架代码中的唯一约束

实体框架中多列的唯一键约束

尝试持久化和具有主键唯一约束的实体时出错

@oneToMany 和 @JoinTable 在 jpa 中具有唯一约束?

如何使用hibernate避免遇到违反唯一约束的问题?

尝试插入具有 1:N 关系的实体时,重复键值违反 EntityFramework 中的唯一约束“PK_Users”错误