c# - Unable to get entity framework to generate a DbUpdateConcurrencyException (Database First) -
i'm trying implement optimistic locking model ef. have column timestamp datatype on tables i'm trying with.
i've tried adding timestamp
attribute on member modifying t4 script. running test , seeing not working, tried adding concurrencycheck
attribute on same member in same way (via t4). however, in neither case generated sql utilize member on updates (shown below). i've set concurrency mode
fixed
on property in edmx designer.
i can see timestamp column in separate select after update not on update itself. i've tried breaking on savechanges()
, changing database record , seeing timestamp value changing after manual update, executing savechanges()
line , executes fine without throwing exception. there i'm missing, need roll own timestamp comparison code, or need world of ef interceptors change sql output? thanks.
the generated sql: (logged via dbcontext.database.log
)
update [dbo].[foo] set [footitle] = @0 ([fooid] = @1) select [fooversion] [dbo].[foo] @@rowcount > 0 , [fooid] = @1
the final version of member after t4 generation:
[timestamp] [concurrencycheck] public byte[] fooversion { get; set; }
what i'm trying ef do:
update [dbo].[foo] set [footitle] = @0 ([fooid] = @1 , [fooversion] = @2)
i decided roll own checking code. it's pretty efficient, though require 2 trips database.
i wrote interface attaches series of partial classes use attach things entities. defines lookup selector entity base class service can use go fetch particular version. no result? return message. if there result entity updates you'd expect.
the interface:
public interface iversionabledbobject<tentity> tentity : class, ivalidatableobject { byte[] version { get; } expression<func<tentity, bool>> lookupselector { get; } }
an implementation example:
public partial class foo : iversionabledbobject<foo> { public byte[] version { { return fooversion; } } public expression<func<foo, bool>> lookupselector { { return foo => foo.fooid == fooid && foo.fooversion == version; } } }
the checking code in base service:
iversionabledbobject<tentity> versionablesource = entity iversionabledbobject<tentity>; if (versionablesource != null) { bool versionexists = innercontext.set<tentity>().where(versionablesource.lookupselector).any(); if (!versionexists) return new validationresult(string.format(fooresources.entityupdateversionconflicterror, bitconverter.toint32(versionablesource.version, 0))); }
the validation result message formatter accepts version trying looked up. returning of validationresult
specific own implementation. if use it, will.
here's generated sql on .any()
:
select case when ( exists (select 1 [c1] [dbo].[foo] [extent1] ([extent1].[fooid] = @p__linq__0) , ([extent1].[fooversion] = @p__linq__1) )) cast(1 bit) else cast(0 bit) end [c1] ( select 1 x ) [singlerowtable1]
interestingly, when update happens, ef still refreshes row version without timestamp
or concurrencycheck
attributes similar sql posted in op.
Comments
Post a Comment