Base solution for your next web application
Open Closed

How to circumvent Abp/Zero database transactions? #7635


User avatar
0
TimMackey created

Is there any interface available in Abp/Zero (Angular/Core) that will allow context.SaveChanges(); to be immediately written to the database, and NOT wait until the thread is exited?

Using UnitOfWork is not an option, as that introduces its own overhead.

I'm seeking a high-performance solution to write one row at a time to my Apb/Zero db.


10 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team

    You can disable the unit of work.

    [UnitOfWork(IsDisabled = true)]
    public virtual void RemoveFriendship(RemoveFriendshipInput input)
    {
        _friendshipRepository.Delete(input.Id);
    }
    
  • User Avatar
    0
    TimMackey created

    Where does this function reside? How and when is it invoked? The Abp documentation page does not answer these questions.

  • User Avatar
    0
    maliming created
    Support Team

    @timmackey see https://aspnetboilerplate.com/Pages/Documents/Unit-Of-Work#unit-of-work-in-detail

  • User Avatar
    0
    TimMackey created

    I implemented the suggested code changes. Records are not committed to the physical db and performance is 3X SLOWER than the same code in ASP.NET.

    Is there anything I might have missed that would be preventing commit or result in degraded performance?

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    #if NETFRAMEWORK
    using DataModelLibrary.Exams;
    using DbContext = DataModelLibrary.Exams.DbContext_Exam;
    #endif
    
    #if NETCOREAPP   // https://docs.microsoft.com/en-us/dotnet/standard/frameworks
    using Abp.Domain.Uow;
    using Abp.EntityFrameworkCore;
    using System.Transactions;
    
    using ngTTM.TtmDataModel;
    using DbContext = ngTTM.EntityFrameworkCore.ngTTMDbContext;
    #endif
    
    // for clarity, all NETFRAMEWORK-specific code has been removed
    namespace JobsLibrary
    {
        public class CreateExamsDemo
        {
            //-----------------------------------------------------------------------------------------
            private readonly IDbContextProvider<DbContext> _dbContextProvider;
            //-----------------------------------------------------------------------------------------
            public CreateExamsDemo(IDbContextProvider<DbContext> dbContextProvider)
            {
                _dbContextProvider = dbContextProvider;
            }
            //-----------------------------------------------------------------------------------------
            [UnitOfWork(IsDisabled = true)]
            // [UnitOfWork(isTransactional: false)]
            public bool Create(string guid, string rootFolder)
            {
                DateTime _StartTime = DateTime.Now;
                try
                {
                    using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Suppress))
                    {
                        DbContext context = _dbContextProvider.GetDbContext();
                        {
                            Exam exam = context.Exams.First(x => x.Guid == guid);
    
                            // not shown are calls to other functions accessing many db tables
                            // the code fragment below illustrates the concept
    
                            List<ExamQuestion> examQuestionsList = new List<ExamQuestion>();
                            // add multiple ExamQuestion to list
                            context.ExamQuestions.AddRange(examQuestionsList);
                            // acquire table "id" values used in next processing steps (not shown)
                            context.SaveChanges();
    
                            // typical execution time in NETFRAMEWORK is approx. 4 minutes
                            // typical execution time in NETCOREAPP is approx. 16 minutes
                            exam.CreateDuration = (float)(DateTime.Now - _StartTime).TotalSeconds;
                            context.SaveChanges();
                            return true;
                        }
                    }
                }
                catch (Exception ex)
                {
                    // Exception handler
                    return false;
                }
                //-----------------------------------------------------------------------------------------
            }
        }
    }
    
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @timmackey

    If the item count in examQuestionsList is too much, you might try to use raw SQL to insert records. Entity Framework is not good with batch inserts.

  • User Avatar
    0
    TimMackey created

    @ismcagdas,

    I'm not confident that converting my app from EF to SQL would be effective. it's a lot of code that would need to be changed, and I'm concerned that SQL updates will not effect until transaction/thread completion after all the changes.

    I'm using EF in ASP.NET Framework 4.5.2 in my original app; excellent performance and the db is updated upon context.SaveChanges(). EF in Zero/Core however has slower performance and the db is NOT updated upon context.SaveChanges(); the db is updated upon transaction/thread completion.

    I think the mystery now is why non-transactional unit of work attributes (as recommended by @maliming) are not working.

  • User Avatar
    0
    maliming created
    Support Team

    I think the mystery now is why non-transactional unit of work attributes (as recommended by @maliming) are not working.

    Note that if a unit of work method calls this RemoveFriendship method, disabling this method is ignored, and it will use the same unit of work with the caller method.

  • User Avatar
    0
    BobIngham created

    @timmackey, implement an sql repository in the entity framework project and call the methods directly from your app service. All of my grid information is read in such a way, sometimes it is simpler and more performant to work directly with the database without the Zero overhead.

  • User Avatar
    0
    ismcagdas created
    Support Team

    @timmackey

    I think the mystery now is why non-transactional unit of work attributes (as recommended by @maliming) are not working.

    Probably becasue your method is not virtual

    public bool Create(

    If you convert to to virtual, probably it will work:

    public virtual bool Create(

  • User Avatar
    0
    TimMackey created

    Converting to virtual solved the issue. See #7550 for complete solution.