Not related to this specific example, but I came across a challenge when trying to use EF and a DateTime field as the concurrency check field. It appears the EF concurrency code doesn't honor the precision setting from the metadata (edmx) i.e. Type="DateTime" Precision="3".
The database datetime field will store a millisecond component within the field (i.e. 2020-10-18 15:49:02.123). Even if you set the original value of the Entity to a DateTime that includes the millisecond component, the SQL EF generates is this:
UPDATE [dbo].[People]
SET [dateUpdated] = @0
WHERE (([PeopleID] = @1) AND ([dateUpdated] = @2))
-- @0: '10/19/2020 1:07:00 AM' (Type = DateTime2)
-- @1: '3182' (Type = Int32)
-- @2: '10/19/2020 1:06:10 AM' (Type = DateTime2)
As you can see, @2 is a STRING representation without a millisecond component. This will cause your updates to fail.
Therefore, if you're going to use a DateTime field as a concurrency key, you must STRIP off the milliseconds/Ticks from the database field when retrieving the record and only pass/update the field with a similar stripped DateTime.
//strip milliseconds due to EF concurrency handling
PeopleModel p = db.people.Where(x => x.PeopleID = id);
if (p.dateUpdated.Millisecond > 0)
{
DateTime d = new DateTime(p.dateUpdated.Ticks / 10000000 * 10000000);
object[] b = {p.PeopleID, d};
int upd = db.Database.ExecuteSqlCommand("Update People set dateUpdated=@p1 where peopleId=@p0", b);
if (upd == 1)
p.dateUpdated = d;
else
return InternalServerError(new Exception("Unable to update dateUpdated"));
}
return Ok(p);
And when updating the field with a new value, strip the milliseconds also
(param)int id, PeopleModel person;
People tbl = db.People.Where(x => x.PeopleID == id).FirstOrDefault();
db.Entry(tbl).OriginalValues["dateUpdated"] = person.dateUpdated;
//strip milliseconds from dateUpdated since EF doesn't preserve them
tbl.dateUpdated = new DateTime(DateTime.Now.Ticks / 10000000 * 10000000);
catch (Exception ex){throw;}
is redundant and you can completely remove it. – Amendatorybook
object has a valid primary key value? Because it hasn't. If it had, it couldn't have been attached afterresult
was found. That's the cause of theDbUpdateConcurrencyException
. Maybe this answer does a half-baked attempt addressing the flaw, but it doesn't really explain much. – Nasya