Breeze / breeze.server.net

Breeze support for .NET servers
MIT License
76 stars 62 forks source link

EFContextProvider 1.4.16 throws DbUpdateConcurrencyException when trying to update Enum value. #8

Closed pawelpawlow closed 6 years ago

pawelpawlow commented 10 years ago

Trying to SaveChanges of a single enum property value update throws System.Data.Entity.Infrastructure.DbUpdateConcurrencyException.

The enum property is defined like this:

        public virtual System.Nullable<StanZleceniaOplaty> Stan { get; set; }

        public enum StanZleceniaOplaty : int
        {
                    Created,
                    Started,
                    Canceled,
                    Rejected,
                    Paid
        }

EntityTypeConfiguration for entity ZlecenieOplaty configures Stan with the following code:

        this
            .Property(p => p.Stan)
                .IsConcurrencyToken()
                .HasColumnType("int"); 

I can see that the SQL generated by EFContextProvider agains the EF 6.1 DB is wrong ([Stan] is not changed, because @0 == @2, @2 has wrong value - should be 0).

exec sp_executesql N'UPDATE [dbo].[ZlecenieOplaty]
SET [Stan] = @0
WHERE (([Id] = @1) AND ([Stan] = @2))
SELECT [NrZlecenia]
FROM [dbo].[ZlecenieOplaty]
WHERE @@ROWCOUNT > 0 AND [Id] = @1',
N'@0 int,@1 int,@2 int',
@0=2,
@1=3,
@2=2

In effect the following exception is thrown.

System.Data.Entity.Infrastructure.DbUpdateConcurrencyException occurred
  HResult=-2146233087
  Message=Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.
  Source=EntityFramework
  StackTrace:
       at System.Data.Entity.Internal.InternalContext.SaveChanges()
       at Alcance.Entities.AlcanceDbContext.SaveChanges() in d:\Develop\alcance\src\dev\Alcance.Data\Model\AlcanceModel.AlcanceDbContext.Connection.cs:line 121
  InnerException: System.Data.Entity.Core.OptimisticConcurrencyException
       HResult=-2146233087
       Message=Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.
       Source=EntityFramework
       StackTrace:
            at System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.ValidateRowsAffected(Int64 rowsAffected, UpdateCommand source)
            at System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.Update()
            at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
            at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesToStore(SaveOptions options, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction)
            at System.Data.Entity.Infrastructure.DbExecutionStrategy.Execute[TResult](Func`1 operation)
            at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesInternal(SaveOptions options, Boolean executeInExistingTransaction)
            at System.Data.Entity.Internal.InternalContext.SaveChanges()
       InnerException:
jtraband commented 10 years ago

I will try to repro, but .... why are you using an Enum as a concurrency column. Enums by their nature have only a very limited number of possible values whereas concurrency columns are traditionally used with datatypes with a very large range of values so that collisions become unlikely. I've never seen an enum as a concurrency value before.

pawelpawlow commented 10 years ago

Thank you Jay. Enum column is used together with the primary key column for concurrency. The Enum column represents state of a document. I don’t want to allow two transactions changing the state of the same document to “paid” at the same time. I allow two transactions changing for example column “notes” at the same time. What would you suggest for my scenario?

steveschmitt commented 6 years ago

The problem was that the OriginalValues inside the EF entity were not being set for Enum types. Finally fixed in 1.6.6.