Handling Concurrency Conflicts with DataGrid with Edit Mode

Hi, my application is made up of a few CRUDs with Radzen Blazr where I feel it is necessary to manage conflicts when modifying users.
The CRUD is made with RadzenDataGrid with edit mode.
I would like to know if I can implement Handling Concurrency Conflicts with edit mode?
IF yes do you have some example?
Thanks in advance to your reply

Optimistic concurrency is an option during data source infer and CRUD pages scaffolding.

I thanks to this information. I don't the use radzen application to make the application. I only use the library of radzen, there are a lot things on it :wink:

So I've created the Timestamp in class and I've put in the PUT method try{} catch{} and I didn't received any throw from EF that there is an error or conflict

public class ProjetModel 
    {
        [Key]
        public int IdProjet { get; set; }
        [Required]
        public DateTime DateProjet { get; set; }
        [Required]
        public string? Title { get; set; }            

        [Timestamp]
        public byte[]? ConcurrencyToken { get; set; }
}

After that I've made the add-migrations initial.

 [HttpPut]
        public async Task<IActionResult> Put(ProjetModel projet)
        {
            var toUpdate = await _context.ProjetModels.FirstOrDefaultAsync(x => x.IdProjet == projet.IdProjet);

            _context.Entry(toUpdate).Property(d => d.ConcurrencyToken).OriginalValue = projet.ConcurrencyToken;

            if (await TryUpdateModelAsync<ProjetModel>(
                toUpdate,
               "Projet",
                s => s.Title, s => s.Type, s => s.Statut, s => s.DateProjet))
            {
                try
                {
                    await _context.SaveChangesAsync();
                    return RedirectToPage("./ppage");
                }
                catch (DbUpdateConcurrencyException ex)
                {
                    var exceptionEntry = ex.Entries.Single();
                    var clientValues = (ProjetModel)exceptionEntry.Entity;
                    var databaseEntry = exceptionEntry.GetDatabaseValues();
                    if (databaseEntry == null)
                    {
                        ModelState.AddModelError(string.Empty, "Unable to save. " +
                            "The line was deleted by another user.");
                        return RedirectToPage("./ppage");

                    }
                    var dbValues = (ProjetModel)databaseEntry.ToObject();
                    await SetDbErrorMessage(dbValues, clientValues);
                    // Save the current ConcurrencyToken so next postback
                    // matches unless an new concurrency issue happens.
                    projet.ConcurrencyToken = (byte[])dbValues.ConcurrencyToken;
                    ModelState.Remove($"{nameof(projet)}.{nameof(projet.ConcurrencyToken)}");
                }
                
            }
            return RedirectToPage("./ppage");
            // _context.Entry(projet).State = EntityState.Modified;
            // await _context.SaveChangesAsync();
            // return NoContent();
        }

        private async Task SetDbErrorMessage(ProjetModel dbValues,
                                         ProjetModel clientValues)
            {

                    if (dbValues.Title != clientValues.Title)
                    {
                        ModelState.AddModelError("Department.Name",
                            $"Current value: {dbValues.Title}");
                    }
                    if (dbValues.Type != clientValues.Type)
                    {
                        ModelState.AddModelError("Department.Budget",
                            $"Current value: {dbValues.Type:c}");
                    }
                    if (dbValues.DateProjet != clientValues.DateProjet)
                    {
                        ModelState.AddModelError("Department.StartDate",
                            $"Current value: {dbValues.DateProjet:d}");
                    }
                    if (dbValues.Statut != clientValues.Statut)
                    {
                        ModelState.AddModelError("Department.StartDate",
                            $"Current value: {dbValues.Statut:d}");
                    }
            ModelState.AddModelError(string.Empty,
                                       "The record you attempted to edit "
                                     + "was modified by another user after you. The "
                                     + "edit operation was canceled and the current values in the database "
                                     + "have been displayed. If you still want to edit this record, click "
                                     + "the Save button again.");
        }

Have you any suggestions how to manage Optimistic concurrency in RadzenDataGrid in edit mode?

Hi, I also tested the put method below.
I this case, EF core will throw an error but there are any errors. If I understand in this context, EF code will compare the timestamp to the one in the database and show error if no match.
Have you any idea what happens with this handling concurrency?

  [HttpPut]
        public async Task<IActionResult> Put(ProjetModel projet)
        { 

            _context.Entry(projet).State = EntityState.Modified;
            await _context.SaveChangesAsync();
            return NoContent();
        }

I already suggested how you can easily get the code for optimistic concurrency.

Thanks to your reply.
But I've made a controller, class model to make the CRUD and add-miggrations
I've implemented handling concurrency in put method when I've do a swagger I received a good answer;

As explained in the first post I use the DataGrid with edit mode

Now I want to return in this page the message from put method

RadzenDataGridColumn TItem="ProjetModel" Property="Title" Title="Title" Width="250px">                           <EditTemplate Context="projet"> 
	<RadzenTextBox @bind-Value="projet.Title" Name="title" MaxLength="80" />
    **<RadzenTextBox @bind-Value="projet.Title" Name="title" MaxLength="80" />** // IT'S HERE THAT I WANT TO ADD  CONCURRENCY INFORMATION

    <RadzenRequiredValidator Component="title" Text="Title is required" Popup="true" />                                                       </EditTemplate>                    
 </RadzenDataGridColumn> 


<RadzenButton Icon="check" ButtonStyle="ButtonStyle.Success" Variant="Variant.Flat" Size="ButtonSize.Medium" Click="@(args => SaveRow(projet))">

@code{

 ProjetModel dev = new ProjetModel();

protected override async Task OnInitializedAsync() 
 {   
  await base.OnInitializedAsync();
   projet = await client.GetFromJsonAsync<ProjetModel[]>("api/projetbe");
   }

async Task SaveRow()
{   
	await client.PutAsJsonAsync("api/projetbe", projet); 
         uriHelper.NavigateTo("ppage");
	projetBEToInsert = null;         
}

}

I would like to know how can I call this information in put method.?

Hi, I didn't use CRUD pages scaffolding because all pages has already done;
As you understood I want to rendering the Concurrency in the razor page in DataGrid with Edit Line Mode.

I've made the put method and this method seems correct. In dev tool I received the data from the controller : api/projetbe. You will find below the picture showing an overview of the controller.
This result is when I've opened two browser page to simulate two users.

I would like to rendering the concurrency as in picture below.

After several attempts I can't display the result for handling concurrency.
Do you have any suggestions how I can do it in RadzenDataGrid with edit mode?
Thanks in advance

I’ve already provided my suggestions and I don’t have anything else to add. Handling concurrency is a complex task with additional code in models, services and the UI - it’s not a single component feature.