Base solution for your next web application
Open Closed

Seeding Tenant Data #6073


User avatar
0
epayday created

I found this support post https://support.aspnetzero.com/QA/Questions/3591 with regards to Seeding Tenant Data.

Got the code working but I am confused on how I can seed the data with the correct Tenant ID.

var defaultTenant = _context.Tenants.IgnoreQueryFilters().FirstOrDefault(t => t.TenancyName == MultiTenancy.Tenant.DefaultTenantName);

The above line of code gives me the default ID of 1.

I know elsewhere you get the current tenant via AbpSession.TenantId but due to my limited knowledge I can't work out how access ApbSession inside my custom code called from DefaultTenantBuilder.cs


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

    Then do you want to give all tenants a seed data or a specific tenant? If it is all you get the collection of tenants directly here, if it is a specific tenant I believe you can know the tenant name in advance

  • User Avatar
    0
    epayday created

    I wish to create seed data when a new tenant is created. What I am attempting to do is create a set of common records all tenants will start with. After that they can do what they want.

    Do I run my seeding code when the DefaultTenantBuilder executes (which I assume runs ONLY when you create a new tenant) ?

    If so do I get the newly created Tenant ID from ?

    defaultTenant = new MultiTenancy.Tenant(AbpTenantBase.DefaultTenantName, AbpTenantBase.DefaultTenantName);
    

    Just to ensure I am not barking up the wrong tree, here is my code sample.

            public void Create()
            {
                CreateDefaultTenant();
    
                new InitialStateDataCreator(_context).Create();
            } 
            ............
            
        class InitialStateDataCreator
        {
            readonly string[] stateArray = {"Queensland", "New South Wales", "Australian Capital Territory",
                                            "Victoria", "Tasmania", "South Australia", "Western Australia",
                                            "Northern Territory" };
            private readonly CrazyCatLadyDemoDbContext _context;
    
            public InitialStateDataCreator(CrazyCatLadyDemoDbContext context)
            {
                _context = context;
            }
    
            public void Create()
            {
                CreateStateData();
            }
    
            private void CreateStateData()
            {
                var defaultTenant = _context.Tenants.IgnoreQueryFilters().FirstOrDefault(t => t.TenancyName == MultiTenancy.Tenant.DefaultTenantName);
                foreach (string state in stateArray)
                {
                    var stateToFind = _context.States.FirstOrDefault(p => p.Name == state);
                    if (stateToFind == null)
                    {
                        _context.States.Add(
                            new State
                            {
                                Name = state,
                                TenantId = defaultTenant.Id
                            });
                    }
                }
            }
        }
    
  • User Avatar
    0
    maliming created
    Support Team

    https://github.com/aspnetzero/aspnet-zero-core/blob/c25d832d74e031ea622b9477f2e8d671a353c597/aspnet-core/src/MyCompanyName.AbpZeroTemplate.Core/MultiTenancy/TenantManager.cs#L164

    https://github.com/aspnetzero/aspnet-zero-core/blob/c25d832d74/aspnet-core/src/MyCompanyName.AbpZeroTemplate.Core/MultiTenancy/Demo/TenantDemoDataBuilder.cs#L67

    I think you can use Repository here to initialize the relevant data.

  • User Avatar
    1
    martin created

    I am actually the OP, I was using the company account and my boss set me up with my own login. Thanks for the starting keywords and code locations by the way maliming they were very helpful.

    Anyway here is what I ended up doing. I am still learning so I think it would be smart to put up a potential solution in case someone else can benefit from this.

    TenantManger.cs

       .
            private readonly TenantSeedDataBuilder _seedDataBuilder;        
            .
            
                        await _demoDataBuilder.BuildForAsync(tenant);
                        await _seedDataBuilder.BuildForAsync(tenant);
    

    TenantSeedDataBuilder.cs

        public class TenantSeedDataBuilder : CrazyCatLadyDemoServiceBase, ITransientDependency
        {
            private readonly IRepository<State, long> _stateRepository;
            private State state;
    
            public TenantSeedDataBuilder(
                IRepository<State, long> stateRepository)
            {
                _stateRepository = stateRepository;
            }
    
            public async Task BuildForAsync(Tenant tenant)
            {
                using (CurrentUnitOfWork.SetTenantId(tenant.Id))
                {
                    BuildForInternal(tenant);
                    await CurrentUnitOfWork.SaveChangesAsync();
                }
            }
    
            private void BuildForInternal(Tenant tenant)
            {
                string[] stateArray = {"Queensland", "New South Wales", "Australian Capital Territory",
                                       "Victoria", "Tasmania", "South Australia", "Western Australia",
                                       "Northern Territory" };
    
                foreach (string item in stateArray)
                {
                    state = new State
                    {
                        TenantId = tenant.Id,
                        Name = item
                    };
                    _stateRepository.Insert(state);
                }
            }
        }
    

    So what this does is create some seed values for states everytime a Tenant is created. Any feedback would be welcome of course. :-)

  • User Avatar
    0
    KarakTheWise created

    Just wanted to say I used @martin solution and it works very well for poplating simple lookup tables. Thanks for sharing.