Base solution for your next web application

Activities of "system15"

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);
        }

Cheers

@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.

  1. Tab 1 data loaded into memory and tab 2 data loaded into memory.
  2. Make changes to tab 1 then save.
  3. Make changes to tab 2 then save (shouldn't let you because the RowVersion should be different).

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.

Showing 11 to 20 of 30 entries