Home > Software design >  Updating Modal for CRUD (React / C# / Entity Framework Core)
Updating Modal for CRUD (React / C# / Entity Framework Core)

Time:12-30

I created a modal for my project. This is my first time creating a full CRUD using C# and Entity Framework Core. Create, read and delete are all working fine but I have been stuck for hours on the Update.

I have worked the problem out via the debugger and it updates exactly how I expect it to, however the issue is thrown at the .CommitAsync(); every time even though the data is updated just like it should!

The error I keep getting back is:

enter image description here

Screenshot of the modal for context:

enter image description here

Service:

    public async Task<bool> UpdateUnitOfMeasure(UnitOfMeasureViewModel view, string userId)
    {
        var UOM = await _unitOfMeasureRepo.GetSingleAsync(uom => uom.Id == view.Id);
        _mapper.Map<UnitOfMeasureViewModel, UnitOfMeasure>(view, UOM);
        UOM.UpdateUserId = userId;
        _unitOfMeasureRepo.Update(UOM);

        foreach(var uos in view.UnitSize)
        {
            UnitOfMeasureSize unitSize = new UnitOfMeasureSize
            {
                Id = _idService.GetIdString(),
                UnitSize = uos,
                UnitOfMeasureId = UOM.Id,
                UpdateUserId = userId,
                TenantId = TenantId,
            };

            _unitOfMeasureSizeRepo.Update(unitSize);
        }

        await _unitOfMeasureRepo.CommitAsync();

        return true;
    }

Controller:

[HttpPut("{id}")]
[Authorize(Permissions.Admin.UnitOfMeasure.Update)]
public async Task<ActionResult> Put(string id, [FromBody] UnitOfMeasureViewModel value)
{
    var retObj = await _service.UpdateUnitOfMeasure(value, await _accountService.GetUserIdFromPrincipal(User));
    return new OkObjectResult(this._resp.packageResponse(retObj));
}

TSX:

private saveUOMLogic = () => {
    if (!this.state.editing){
    this.adminStore.saveUnitOfMeasure(this.state.unitOfMeasure)
        .then(
            (data: any) => {
                if (data) {
                    const message = 'Changes have been saved';
                    this.MessageStore.addMessage(
                        message,
                        'success'
                    );
                    this.adminStore.getUnitOfMeasures();
                }
            },
            (error: any) => {
                this.MessageStore.addMessage(
                    error.toString(),
                    'there was an erorr in saving UOM'
                );
            }
        );
    } else {
        this.adminStore.putUnitOfMeasure(this.state.unitOfMeasure)
        .then(
            (data: any) => {
                if (data) {
                    const message = 'Changes have been saved';
                    this.MessageStore.addMessage(
                        message,
                        'success'
                    );
                    this.adminStore.getUnitOfMeasures();
                }
            },
            (error: any) => {
                this.MessageStore.addMessage(
                    error.toString(),
                    'there was an erorr in saving UOM'
                );
            }
        );
    }
}

Entities:

[Table("UnitOfMeasure")]
public class UnitOfMeasure : IEntityBase, IAuditBase
{
    [Key]
    [Column("UnitOfMeasureId")]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public string Id { get; set; }

    [Required]
    [ForeignKey("TenantId")]
    public string TenantId { get; set; }
    [JsonIgnore]
    public virtual Tenant Tenant { get; set; }
    public string Name { get; set; }
    public virtual IEnumerable<UnitOfMeasureSize> UnitOfMeasureSizes { get; set; }

    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public DateTime CreateDate { get; set; } = DateTime.UtcNow;
    [StringLength(255)]
    public string CreateUserId { get; set; }
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public DateTime UpdateDate { get; set; }
    [StringLength(255)]
    public string UpdateUserId { get; set; }
}

[Table("UnitOfMeasureSize")]
public class UnitOfMeasureSize : IEntityBase, IAuditBase
{
    [Key]
    [Column("UnitOfMeasureSize")]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public string Id { get; set; }

    [Required]
    [ForeignKey("TenantId")]
    public string TenantId { get; set; }
    [JsonIgnore]
    public virtual Tenant Tenant { get; set; }

    [Required]
    [ForeignKey("UnitOfMeasureId")]
    public string UnitOfMeasureId { get; set; }
    public virtual UnitOfMeasure UnitOfMeasure { get; set; }

    [Required]
    public int UnitSize { get; set; }

    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public DateTime CreateDate { get; set; } = DateTime.UtcNow;
    [StringLength(255)]
    public string CreateUserId { get; set; }
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public DateTime UpdateDate { get; set; }
    [StringLength(255)]
    public string UpdateUserId { get; set; }
}

CodePudding user response:

Based on your model, I do not see how do you plan to update UnitOfMeasureSize, only Insert or Delete can be done here if view.UnitSize is just int.

Here code with should work without repositories. If it works, try to map to your abstraction.

public async Task<bool> UpdateUnitOfMeasure(UnitOfMeasureViewModel view, string userId)
{
    var UOM = await _context.UnitOfMeasure
        .Include(om => om.UnitOfMeasureSizes) // important
        .FirstAsync(om => uom.Id == view.Id));

    UON.TenantId = TenentId;
    UON.Name = view.Name;
    UON.UpdateDate = DateTime.Now;
    UON.UpdateUserId = userId;

    foreach(var uos in view.UnitSize)
    {
        var unitSize = UON.UnitOfMeasureSizes.FirstOrDefault(ms => ms.UnitSize == uos);
        if (unitSize == null)
        {
            unitSize = new UnitOfMeasureSize
            {
                Id = _idService.GetIdString(),
                CreateUserId = userId,
                TenantId = TenantId,
                UnitSize = uos
            };
            UON.UnitOfMeasureSizes.Add(unitSize);
        }
    }

    await _context.SaveChangesAsync();

    return true;
}

CodePudding user response:

I found a solution to this problem though I do think @svyatosiav's answer would also work.

Unit Sizes have a foreign key relationship with Unit of Measure. Since I am doing this in a service and not in a db context, I needed to commit the changes. I was running into the issue that before I would CommitAsync(), unit sizes would update with the UOM repo, then again when I mapped through the unit sizes. Therefore it was updating twice and hence the error, Unit Sizes were already updated so it couldn't be updated twice. Here is my solution:

public async Task<bool> UpdateUnitOfMeasure(UnitOfMeasureViewModel view, string userId)
    {
        var UOM = await _unitOfMeasureRepo.GetSingleAsync(uom => uom.Id == view.Id);
        this._unitOfMeasureSizeRepo.DeleteWhere(uos => uos.UnitOfMeasureId == UOM.Id);
         _mapper.Map<UnitOfMeasureViewModel, UnitOfMeasure>(view, UOM);
         UOM.UpdateUserId = userId;
         _unitOfMeasureRepo.Update(UOM);
         foreach(var uos in view.UnitSize)
         {
         UnitOfMeasureSize unitSize = new UnitOfMeasureSize
             {
                 Id = _idService.GetIdString(),
                 UnitSize = uos,
                 UnitOfMeasureId = UOM.Id,
                 UpdateUserId = userId,
                TenantId = TenantId,
             };
             _unitOfMeasureSizeRepo.Add(unitSize);
         }
         await _unitOfMeasureRepo.CommitAsync();
         return true;
    }

By deleting the Unit Sizes, I could then just map and re-add the new unit sizes without an issue.

  • Related