I have a project that I developed with EF Core and react. What I want is to be able to give the second person an "updated before" error if two different users open the screen at the same time and update the same data at different times. But when I apply it as in the pictures, it does not catch any errors and updates the db. A unique new rowversion is also assigned to the db.
implementation of what I want in the console app
The points I updated in my project while implementing.
on modelcreating:
modelBuilder.Entity<User>().Property(e => e.RowVersion)
.IsRequired()
.IsRowVersion()
.IsConcurrencyToken();
entity:
public class User : AbpUser<User>
{
[Timestamp]
public byte[] RowVersion { get; set; }
}
the code i expect to give an error:
public override async Task<UserDto> UpdateAsync(UserDto input) {
CheckUpdatePermission();
//input.RowVersion = new byte[] { 0, 0, 0, 0, 0, 0, 7, 215 };
var user = await _userManager.GetUserByIdAsync(input.Id);
//MapToEntity(input, user);
//user.UserName = "hh";
//user.RowVersion = new byte[] { 1, 2, 0, 0, 0, 0, 9, 85};
user.RowVersion[1] =55;
try
{
CheckErrors(await _userManager.UpdateAsync(user));
}
catch (Exception e)
{
throw new UserFriendlyException(e.Message);
}
if (input.RoleNames != null)
{
CheckErrors(await _userManager.SetRolesAsync(user, input.RoleNames));
}
return await GetAsync(input);
}
CodePudding user response:
If you are using ABP framework (and you use the framework supplied EfCoreRepository base class for your repository implementation) this is all handled for you when your entity implements the IHasConcurrencyStamp
interface. Use this instead of RowVersion.
Make sure you are assigning the concurrency stamp value to the entities ConcurrencyStamp
property (supplied by the caller) before calling update on the repository/DbContext.
CodePudding user response:
When I edited the userappservice I specified in the question as follows, rowversion threw the error and my problem was solved. But I don't know if updating with such a method instead of updateasync will cause any problems.
[UnitOfWork(isTransactional:false)]
public override async Task<UserDto> UpdateAsync(UserDto input)
{
CheckUpdatePermission();
var user = await _userManager.GetUserByIdAsync(input.Id);
var options = new DbContextOptionsBuilder<DevFrameTemplateDbContext>()
.UseSqlServer(new SqlConnection("customsqlconnectıonstring"))
.Options;
using (DevFrameTemplateDbContext db = new
DevFrameTemplateDbContext(options))
{
User p = await db.Users.AsNoTracking().FirstAsync(x => x.Id == input.Id);
p.UserName = "Guncellendiiiiiiii";
p.RowVersion = new byte[] { 0, 0, 0, 0, 0, 0, 39, 22 }; // hatalı verinde error. doğru verince kaydediyor.
db.Users.Update(p);
await db.SaveChangesAsync();
}
MapToEntity(input, user);
//try
//{
//CheckErrors(await _userManager.UpdateAsync(user));
//}
//catch (Exception e)
//{
//throw new UserFriendlyException(e.Message);
//}
if (input.RoleNames != null)
{
CheckErrors(await _userManager.SetRolesAsync(user, input.RoleNames));
}
return await GetAsync(input);
}
Thanks for supports .
- Looking forward to your comments to make this working method short enough.