ApplyAbpConceptsForDeletedEntity code is the same as above
@ismcagdas Nope can you let me know any useful changes that may help.
@aaron yes it's similar I'm trying to apply the solution of:
protected override void ApplyAbpConceptsForModifiedEntity(EntityEntry entry, long? userId, EntityChangeReport changeReport)
{
if (entry.Entity is MyRowVersionEntity)
{
entry.OriginalValues["RowVersion"] = entry.CurrentValues["RowVersion"];
}
base.ApplyAbpConceptsForModifiedEntity(entry, userId, changeReport);
}
To
protected override void ApplyAbpConceptsForDeletedEntity(EntityEntry entry, long? userId, EntityChangeReport changeReport)
{
base.ApplyAbpConceptsForDeletedEntity(entry, userId, changeReport);
}
@aaron is there a way of making MyRowVersionEntity more generic so I don't need to specify each entity?
@aaron it's using EntityframeworkCore as the title says.
Hi there I'm trying to simulate concurrency using the two tab approach e.g.
Simulating concurrency: The only way that I can get the simulating to work is by setting a breakpoint on the ObjectMapper.Map(input, accountStatus); and then modifying the entity that is being saved in the database using another tool such as SQL Management Studio running an Update SQL script.
Update method:
private async Task Update(CreateOrEditAccountStatusDto input) { var accountStatus = await _accountStatusRepository.FirstOrDefaultAsync((Guid)input.Id); ObjectMapper.Map(input, accountStatus); }
Current status: At the moment the only way I can get the two tab approach test case to work is by manually doing a RowVersion comparison inside the entity then throwing an exception if the byte arrays don't match. I want to handle the comparison at entityframework level so I don't have to make a code change to each entity. Please let me know where I'm going wrong.
Issue: Why doesn't the DbUpdateConcurrencyException get thrown on the two tab approach?
Got it working I adjusted how my simulated testing was done. Reference from https://docs.microsoft.com/en-us/ef/ef6/saving/concurrency
I still can't get project to throw DbUpdateConcurrencyException inside the ASP.NET Zero project. Any ideas where I'm going wrong?
My update method looks like this:
private async Task Update(CreateOrEditAccountStatusDto input)
{
var accountStatus = await _accountStatusRepository.FirstOrDefaultAsync((Guid)input.Id);
ObjectMapper.Map(input, accountStatus);
}
DbContext looks like this
using MyProject.DevExpressDashboard;
using MyProject.Wellspect;
using MyProject.CustomerDetail;
using MyProject.Reporting;
using Abp.IdentityServer4;
using Abp.Zero.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using MyProject.Authorization.Roles;
using MyProject.Authorization.Users;
using MyProject.Chat;
using MyProject.Editions;
using MyProject.Friendships;
using MyProject.MultiTenancy;
using MyProject.MultiTenancy.Accounting;
using MyProject.MultiTenancy.Payments;
using MyProject.Storage;
using System.Linq;
using System.Threading.Tasks;
using System.Threading;
using Abp.Domain.Uow;
using Abp.UI;
using System;
namespace MyProject.EntityFrameworkCore
{
public class MyProjectDbContext : AbpZeroDbContext<Tenant, Role, User, MyProjectDbContext>, IAbpPersistedGrantDbContext
{
public virtual DbSet<EntityHistory> EntityHistory { get; set; }
public virtual DbSet<AccountStatus> AccountStatuses { get; set; }
public virtual DbSet<BinaryObject> BinaryObjects { get; set; }
public virtual DbSet<ChatMessage> ChatMessages { get; set; }
public virtual DbSet<SubscriptionPayment> SubscriptionPayments { get; set; }
public MyProjectDbContext(DbContextOptions<MyProjectDbContext> options)
: base(options)
{
}
public override int SaveChanges()
{
try
{
return base.SaveChanges();
}
catch (DbUpdateConcurrencyException innerException)
{
throw new UserFriendlyException("Concurrency exception!", innerException.Message, innerException);
}
}
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
{
try
{
return await base.SaveChangesAsync(cancellationToken);
}
catch (DbUpdateConcurrencyException ex)
{
var entity = ex.Entries.Single().GetDatabaseValues();
if (entity == null)
{
throw new UserFriendlyException("The entity being updated is already deleted by another user.");
}
else
{
throw new UserFriendlyException("The entity being updated has already been updated by another user.");
}
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// modelBuilder.Entity<EntityHistory>(E =>
// {
// E.HasIndex(e => new { e.TenantId });
// });
modelBuilder.Entity<BinaryObject>(b =>
{
b.HasIndex(e => new { e.TenantId });
});
modelBuilder.Entity<ChatMessage>(b =>
{
b.HasIndex(e => new { e.TenantId, e.UserId, e.ReadState });
b.HasIndex(e => new { e.TenantId, e.TargetUserId, e.ReadState });
b.HasIndex(e => new { e.TargetTenantId, e.TargetUserId, e.ReadState });
b.HasIndex(e => new { e.TargetTenantId, e.UserId, e.ReadState });
});
modelBuilder.Entity<Friendship>(b =>
{
b.HasIndex(e => new { e.TenantId, e.UserId });
b.HasIndex(e => new { e.TenantId, e.FriendUserId });
b.HasIndex(e => new { e.FriendTenantId, e.UserId });
b.HasIndex(e => new { e.FriendTenantId, e.FriendUserId });
});
modelBuilder.Entity<Tenant>(b =>
{
b.HasIndex(e => new { e.SubscriptionEndDateUtc });
b.HasIndex(e => new { e.CreationTime });
});
modelBuilder.Entity<SubscriptionPayment>(b =>
{
b.HasIndex(e => new { e.Status, e.CreationTime });
b.HasIndex(e => new { e.PaymentId, e.Gateway });
});
modelBuilder.Entity<AccountStatus>()
.Property(a => a.RowVersion)
.IsRowVersion();
}
}
}
Thanks yekalkan. I don't seem to be able to open the link however.