Open Closed

Is there a more efficient way to do this? #11128


0
marble68 created

Prerequisites

11.0 CORE MVC

I have background job that is pulling data - this is what I'm doing to try and shuffle a considerable amount of data over.

So I have this repeating over and over in the code, making it smell very bad.

I think I've missed something, this seems way too complicated?

Probably the thing to do is refactor this in a service.

Thanks in advance for any tips or tricks!

            using (var uowManager = IocManager.Instance.ResolveAsDisposable<IUnitOfWorkManager>())
                        {
                            using (var permUow = uowManager.Object.Begin())
                            {
                                _context = uowManager.Object.Current.GetDbContext<inzibackendDbContext>(MultiTenancySides.Host);
                                if (_context.Tenants.AsNoTracking().IgnoreQueryFilters().Any(t => t.TenancyName.Equals(_args.NewTenancyName)))
                                    return false;


                                using (var _sessionObj = IocManager.Instance.ResolveAsDisposable<IAbpSession>())
                                {
                                    _session = _sessionObj.Object;
                                    _session.Use(args.TenantId, args.UserId);
                                   //// Business steps here that create the rec object
                                    _context.Records.Add(rec);
                                    _context.SaveChanges();
                                }
                                await permUow.CompleteAsync();
                            }
                        }

3 Answer(s)
  • 0
    ismcagdas created
    Support Team

    Hi @marble68

    I couldn't understand the repeating part but if you have such a code block and you are using in both in background jobs and in your app, then you can create a domain service and use it from both from background job and web app.

  • 0
    marble68 created

    To clarify, here's what I'm trying to do:

    Background

    I have a legacy, non aspnetzero project. I am trying to import data from the old system into this new project.

    First, I have to create a client and admin user, then I have to create some default entities, then I have to create the users from the old system, and import data from there. This data includes large binary objects (PDFs, for example).

    This process takes a significant amount of time. If I do this in the migrator, it succeeds because it locks the database and imports the data.

    While this works, it makes applying updates painfully slow and makes me take down the system to import more data. One cient import can take as long as 30 minutes.

    Challenges

    First challenge is if I create the tenant with an admin user, the app services complain that the user I try and use to import objects doesn't have permissions.

    For example, if my UOW uses the create tenent with admin user. This succeeds, but I cannot create a new UOW, tell the session to use that new admin's ID to create entities. I get 'not authorized'.

    That entire job has to 'complete' before the application services will "see" the new admin user and their permissions.

    I'm not sure, but I think this is because the background job is run as a unit of work.

    Secondly, when importing the large files, as a single unit of work, the page for the entity is unresponsive (likely the table is locked).

    Lastly, this import takes a long time. If I do it as a background task, the engine tries to run the task before it completes again. This makes me think I should have my background register as a singleton? Maybe have two - where a singleton kicks off the import and returns success as having run? I'm not sure.

    What I'm trying to do

    The goal is, as host, to kick off an import from the old system after it launches, and have the job create the tenant and setup the users, etc.

    1. It'd create the tenant with an admin user
    2. It'd create tenant admin accounts from users in the old system
    3. It'd construct entities for the new tenant based on data in the old system
    4. it'd create tenant user accounts from the users in the old system
    5. It'd import tenant user data from the old system

    As a background task this takes way too long. As a migration task this takes way too long.

    I need to find a way to manually start this process after the system starts, and have it run in the background and be allowed to finish without timing out or running again.

    I think my singleton "import manager" approach is the way, but I'm just not sure how to get there yet.

    Maybe a singletone migrate control in the framework core project. Then, in core, a domain service that uses that. Then, I'd have a backgroundjob that could be started, that'd use the domain service. Since the migrate control is a singleton, the domain service would start an import, or fail if one is already running (based on migrate control's state).

    the migrate control singleton could then use units of work to go through each step, each account, each entity.

    Does this sound like a sound approach?

  • 0
    ismcagdas created
    Support Team

    Hi,

    If you want to operate on behalf of a different user, you can use https://aspnetboilerplate.com/Pages/Documents/Abp-Session#user-identifier. In this way, you can set TenantId and UserId on session, so you will not get authorization error.

    Maybe a singletone migrate control in the framework core project. Then, in core, a domain service that uses that. Then, I'd have a backgroundjob that could be started, that'd use the domain service. Since the migrate control is a singleton, the domain service would start an import, or fail if one is already running (based on migrate control's state).

    This sounds better if you want to start teh migration process manually.