I really need some help i) to understand the mechanism of optimistic and ii) help me to get the modification of put method
It is impossible to know what you are thinking, what you know, what you don't know... What I do know from your many threads is the subject of your posts are never the actual problem. Maybe your test is faulty or some other problem.
Anyway, I wrote an example based on your code and the [Timestamp] attribute functions exactly as documented.
Model
public class ProjetModel
{
[Key]
public int ProjetId { get; set; }
[Required]
public DateTime DateProjet { get; set; }
[Required]
public string? Title { get; set; }
public string? Type { get; set; }
public string? Level { get; set; }
public bool? IsCompleted { get; set; }
public string? Statut { get; set; }
public int ProjetCount { get; set; }
public string? ProjetCountId
{
get
{
return $"{ProjetCount.ToString().PadLeft(3, '0')}";
}
set { }
}
[Timestamp]
public byte[]? ConcurrencyToken { get; set; }
public List<ActionItemProjet>? ActionItemProjets { get; set; }
}
public class ActionItemProjet
{
[Key]
public int ActionItemProjetId { get; set; }
public string ActionItemProjetName { get; set;}
public int? ProjectId { get; set; }
public ProjetModel? ProjetModel { get; set; }
}
I let Visual Studio scaffold the controller and I modified the GET actions to Include the ActionItemProjets collection.
[Route("api/[controller]")]
[ApiController]
public class ProjetModelsController : ControllerBase
{
private readonly ApplicationDbContext _context;
public ProjetModelsController(ApplicationDbContext context)
{
_context = context;
}
// GET: api/ProjetModels
[HttpGet]
public async Task<ActionResult<IEnumerable<ProjetModel>>> GetProjetModels()
{
if (_context.ProjetModels == null)
{
return NotFound();
}
return await _context.ProjetModels
.Include(a =>a.ActionItemProjets).ToListAsync();
}
// GET: api/ProjetModels/5
[HttpGet("{id}")]
public async Task<ActionResult<ProjetModel>> GetProjetModel(int id)
{
if (_context.ProjetModels == null)
{
return NotFound();
}
var projetModel = await _context.ProjetModels
.Include(a => a.ActionItemProjets)
.SingleOrDefaultAsync(p => p.ProjetId == id);
if (projetModel == null)
{
return NotFound();
}
return projetModel;
}
// PUT: api/ProjetModels/5
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
[HttpPut("{id}")]
public async Task<IActionResult> PutProjetModel(int id, ProjetModel projetModel)
{
if (id != projetModel.ProjetId)
{
return BadRequest();
}
_context.Entry(projetModel).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!ProjetModelExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
// POST: api/ProjetModels
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
[HttpPost]
public async Task<ActionResult<ProjetModel>> PostProjetModel(ProjetModel projetModel)
{
if (_context.ProjetModels == null)
{
return Problem("Entity set 'ApplicationDbContext.ProjetModels' is null.");
}
_context.ProjetModels.Add(projetModel);
await _context.SaveChangesAsync();
return CreatedAtAction("GetProjetModel", new { id = projetModel.ProjetId }, projetModel);
}
// DELETE: api/ProjetModels/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteProjetModel(int id)
{
if (_context.ProjetModels == null)
{
return NotFound();
}
var projetModel = await _context.ProjetModels.FindAsync(id);
if (projetModel == null)
{
return NotFound();
}
_context.ProjetModels.Remove(projetModel);
await _context.SaveChangesAsync();
return NoContent();
}
private bool ProjetModelExists(int id)
{
return (_context.ProjetModels?.Any(e => e.ProjetId == id)).GetValueOrDefault();
}
}
Swagger is used to test EF's optimistic concurrency . First the GET by Id action is called to get ProjetId = 1.
[
{
"projetId": 1,
"dateProjet": "2023-09-15T07:37:13.8697323",
"title": "concurrency test 1",
"type": "Type 1",
"level": "Level 1",
"isCompleted": false,
"statut": "Statut 1",
"projetCount": 0,
"projetCountId": "000",
"concurrencyToken": "AAAAAAAAB9I=",
"actionItemProjets": [
{
"actionItemProjetId": 1,
"actionItemProjetName": "ActionItemProjetName 1",
"projectId": null,
"projetModel": null
},
{
"actionItemProjetId": 2,
"actionItemProjetName": "ActionItemProjetName 2",
"projectId": null,
"projetModel": null
}
]
}
]
Next, the concurrencyToken is changed to AAAAAAAAB9A= to force a concurrency exception. Finally, the payload is summitted to the PUT action. The result is an exception as expected.
Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: The database operation was expected to affect 1 row(s), but actually affected 0 row(s); data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
Perhaps try debugging your code and paying closer attention to what you're doing and what the code is doing.