Open Closed

AbpException vs EfCoreException. #1095


User avatar
0
KuldeepRathi created

Hi,

We are getting issue with Exceptions while using ABP InsertSync.
For any error/exception came from SQL not getting moved in exception code and not going in catch statement. This is happening whenever we are passing false in Repository.InsertAsync().

As shown below in Option 1 code. Please suggest, we need to send custom error number like - throw new CivitException(ex.Message, "2601");

Same is working fine if we are calling direct EfCoreException

-------------------------------------------------------------------- +@ AbpException Code starts -------------------------------------------------------------------- //Option1 :- passing inner async parameter as "false".

public async Task AddOrganization(OrganizationDto input)
        {
            try
            {

                var data = ObjectMapper.Map<OrganizationDto, Setup.Organization.Organization>(input);                                
                await _orgContactRepository.InsertAsync(data, false);
                
            }
        catch (DbUpdateException ex)
            {
                throw new CivitException(ex.Message, "2601");
            }
        }

//Option2 :- passing inner async parameter as "true"

public async Task AddOrganization(OrganizationDto input)
        {
            try
            {

                var data = ObjectMapper.Map<OrganizationDto, Setup.Organization.Organization>(input);                
                await _orgContactRepository.InsertAsync(data, true);                
                
            }
            catch (DbUpdateException ex)
            {
                throw new CivitException(ex.Message, "2601");
            }
        }

------------------------------------ +@ AbpException Code Ends --------------------------------------------------------------------

----------------------------------- +@ EFCoreException Code starts --------------------------------------------------------------------

        public override int SaveChanges()
        {
            try
            {
                
                var data=base.SaveChanges();
                return data;
            }
            catch (DbUpdateException e)
            {
                Console.WriteLine(e);
                throw;
            }
        }

------------------------------------------------ +@ EFCoreException Code ends --------------------------------------------------------------------


5 Answer(s)
  • User Avatar
    0
    alper created
    Support Team Director

    What's the stacktrace? You haven't mentioned about the exception

  • User Avatar
    0
    KuldeepRathi created

    What's the stacktrace? You haven't mentioned about the exception

    Do you need stacktrace? Situation in Steps-

    1. Calling InsertSync() function and Passing False as parameter {as mentioned in below sample code}
    2. If any exception comes then it should go to Catch{} loop.
    3. But currently it is not going.
    4. If we are using plain 'DbUpdateException' of EFCore, then it is raising Ex.message {Sample code added in Previou/ above message}
    
    public async Task AddOrganization(OrganizationDto input)
            {
                try
                {
    
                    var data = ObjectMapper.Map<OrganizationDto, Setup.Organization.Organization>(input);                                
                    ~~await _orgContactRepository.InsertAsync(data, false);~~
                    
                }
            **catch (DbUpdateException ex)
                {
                    throw new CivitException(ex.Message, "2601");
                }**
            }
    
  • User Avatar
    0
    alper created
    Support Team Director

    This is EF Core default behaviour. When there's DbUpdateException, the default exception handler only handles An internal error occurred during your request. If you need the details of the exception you need to cast it, or you need to catch DbUpdateException. Check out this https://stackoverflow.com/questions/22490842/finding-the-reason-for-dbupdateexception

    
            try
            {
                await _orgContactRepository.InsertAsync(data, false);
            }
            catch (DbEntityValidationException vex)
            {
                var exception = HandleDbEntityValidationException(vex);
              
                throw new UserFriendlyException("Ooppps! This record is not valid..");
            }
            catch(DbUpdateException dbu)
            {
                 var builder = new StringBuilder("A DbUpdateException was caught while saving changes.");
    
                try
                {
                    foreach (var result in dbu.Entries)
                    {
                        builder.AppendFormat("Type: {0} was part of the problem. ", result.Entity.GetType().Name);
                    }
                }
                catch (Exception e)
                {
                    builder.Append("Error parsing DbUpdateException: " + e.ToString());
                }
    
                string message = builder.ToString();
                return new Exception(message, dbu);
            
                  throw new UserFriendlyException("Ooppps! Error occured while saving the record.");
            }
            
             
    
  • User Avatar
    1
    alper created
    Support Team Director

    My previous code will also not work in your case. I'll explain the structure, why it doesn't work as you expect and what you can do for a solution;

    PROBLEM:

    The below code executes InsertAsync method with saveChanges=false. This means the entity org will be set as inserted record to the EF Core tracking system. At this point no real insert operation is done. So you'll leave the method without getting any exception because still no database operations has been done. Right after you leave the method, the framework calls SaveChanges method of the EF Core's DbContext class. It discovers any changes to the entity instances and applies to the database. And you get exception at this point. But you already left the try-catch block and HTTP-500: An internal error occured exception will be thrown to the UI.

    public async Task AddOrganizationAsync(Organization org) 
    {
        try 
        {
            await _organizationRepository.InsertAsync(org, false);
        } 
        catch (DbUpdateException ex) {
            throw new MyCustomException(ex.Message, "2601");
        }
    }
    

    SOLUTION:

    If you want to catch the exception in a try-catch block you need to save the changes before leaving the try-catch block. If you have several database operations you can call SaveChanges one time when you finish all the database operations.

    public async Task AddOrganizationAsync(Organization org) 
    {
        try 
        {
            await _organizationRepository.InsertAsync(org, false);
            await _organizationMemberRepository.InsertAsync(org.Members, false);
            await _organizationInvoices.UpdateAsync(org.Invoices, false);
            await _organizationStatistics.DeleteAsync(org.DeletedSomeId);
            //and other DB operations...
            
            //apply changes to the database, you can handle exception at this point
            await UnitOfWorkManager.Current.SaveChangesAsync(); 
        } 
        catch (DbUpdateException ex) {
            throw new MyCustomException(ex.Message, "2601");
        }
    }
    

    Documents:

    • https://docs.abp.io/en/abp/latest/Unit-Of-Work#savechangesasync
    • https://docs.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.dbcontext.savechanges?view=efcore-5.0
  • User Avatar
    0
    ServiceBot created
    Support Team Automatic process manager

    This question has been automatically marked as stale because it has not had recent activity.

Made with ❤️ on ABP v9.1.0-preview. Updated on November 19, 2024, 12:56