I Have the following entity, I am trying to apply the concept of soft delete by adding a shadow property ("IsDeleted") when I run my controller I get the following error,
fail: Microsoft.EntityFrameworkCore.Database.Command[20102] Failed executing DbCommand (8ms) [Parameters=[@p4='3333', @p0='0001-01-01T00:00:00.0000000+00:00', @p1='True', @p2='2', @p5='0x00000000000007D3' (Size = 8), @p3='3c975d79-6ebd-4a77-9998-feb438f16ddc' (Size = 450)], CommandType='Text', CommandTimeout='180'] SET NOCOUNT ON; UPDATE [PatientsRegistry] SET [DateCreated] = @p0, [IsDeleted] = @p1, [RecordId] = @p2, [UserId] = @p3 WHERE [PatientFileId] = @p4 AND [RowVersion] = @p5; SELECT [RowVersion] FROM [PatientsRegistry] WHERE @@ROWCOUNT = 1 AND [PatientFileId] = @p4; System.Data.SqlClient.SqlException (0x80131904): Cannot update identity column 'RecordId'.
Why is EF trying to update my Id column on soft delete?
[Table ("PatientsRegistry")] public class PatientRegistry { [DatabaseGenerated (DatabaseGeneratedOption.Identity)] [Display (Name = "Record Id")] public long RecordId { get; set; } [Key, DatabaseGenerated (DatabaseGeneratedOption.None)] [Display (Name = "Patient File Number")] public long PatientFileId { get; set; } public DateTimeOffset DateCreated { get; set; } [Timestamp] public byte[] RowVersion { get; set; } public virtual ICollection<PartnerRegistry> Partners { get; set; } public string UserId { get; set; } public virtual ApplicationUser User { get; set; } }
My model builder,
builder.Entity<PatientRegistry> () .Property<bool> ("IsDeleted"); builder.Entity<PatientRegistry> () .HasQueryFilter (r => EF.Property<bool> (r, "IsDeleted") == false);
and my controller,
[HttpDelete] public async Task<IActionResult> DeletePatient (long fileId) { var patient = await repository.GetPatient (fileId); if (patient == null) { ModelState.AddModelError (string.Empty, "The patient does not exist in the database"); return StatusCode (404, DataObjectExtentions.FormatErrorResponse (ModelState)); } repository.RemovePatientFromRegistry (patient); await unitOfWork.CompleteAsync (); SuccessResponseResource response = new SuccessResponseResource { // SuccessMessage = patient.FirstName + " " + patient.LastName + " has been deleted successfully!", DataResponse = null }; return StatusCode (200, response); }
unitOfWork.CompleteAsync() is,
public async Task CompleteAsync () { var audit = new Audit (); audit.CreatedBy = ""; // user login Id await context.SaveChangesAsync (audit); }
This is how I am overriding my saving routine,
public override int SaveChanges (bool acceptAllChangesOnSuccess) { OnBeforeSaving (); return base.SaveChanges (acceptAllChangesOnSuccess); } public override Task<int> SaveChangesAsync (bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default (CancellationToken)) { OnBeforeSaving (); return base.SaveChangesAsync (acceptAllChangesOnSuccess, cancellationToken); } private void OnBeforeSaving () { foreach (var entry in ChangeTracker.Entries<PatientRegistry> ()) { switch (entry.State) { case EntityState.Added: entry.CurrentValues["IsDeleted"] = false; break; case EntityState.Deleted: entry.State = EntityState.Modified; entry.CurrentValues["IsDeleted"] = true; break; } }