Hi -
We are trying to create a new tenant in a new database and we get the below error :
Castle.MicroKernel.ComponentActivator.ComponentActivatorException: ComponentActivator: could not instantiate XX.XXXXX.EntityFramework.XXXXXXXDbContext ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Data.SqlClient.SqlException: CREATE DATABASE statement not allowed within multi-statement transaction.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout, Boolean asyncWrite) at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource
1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at System.Data.Entity.Infrastructure.Interception.InternalDispatcher1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func
3 operation, TInterceptionContext interceptionContext, Action3 executing, Action
3 executed)
at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.NonQuery(DbCommand command, DbCommandInterceptionContext interceptionContext)
at System.Data.Entity.SqlServer.SqlProviderServices.<>c__DisplayClass1a.b__19(DbConnection conn)
at System.Data.Entity.SqlServer.SqlProviderServices.<>c__DisplayClass33.b__32()
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.<>c__DisplayClass1.b__0()
at System.Data.Entity.SqlServer.Def...
CLOSE
This error doesn't appear everytime but have started coming more often.
Can you let me know what could be the issue ?
Thanks, Partha
4 Answer(s)
-
0
Any update on this ? I am really having a hard time figuring out the issue
-
0
Hi,
We didn't have this error before ?
Does it happen with same connectionString ? First you get error then after a few trials you manage to create tenant and database ?
And is your Sql Server on a local server ?
-
0
Below is the code which we wrote for creating the Tenant. We copied from the existing code and made some modification. We are adding an Organization Id to the tenant.
Also it's withing the same database and the database is not local.
public async Task<int> CreateWithAdminUserAsync(string tenancyName, string name, string adminPassword, string adminEmailAddress, bool isActive, int? editionId, bool shouldChangePasswordOnNextLogin, bool sendActivationEmail, long? organizationId, int? sourcetenantId, List<string> entityList) { int newTenantId; long newAdminId; using (var uow = _unitOfWorkManager.Begin(TransactionScopeOption.RequiresNew)) { var connectionstringUnit = await (from org in _organizationRepository.GetAll() join constr in _connectionStringRepository.GetAll() on org.ConnectionStringId equals constr.Id where org.Id == organizationId select constr).FirstOrDefaultAsync(); //Create tenant var tenant = new Tenant(tenancyName, name) { IsActive = isActive, EditionId = editionId, ConnectionString = ReferenceEquals(connectionstringUnit, null) ? null : connectionstringUnit.ConnectionString, OrganizationUnitId = organizationId }; CheckErrors(await CreateAsync(tenant)); await _unitOfWorkManager.Current.SaveChangesAsync(); //To get new tenant's id. //Create tenant database _abpZeroDbMigrator.CreateOrMigrateForTenant(tenant); //We are working entities of new tenant, so changing tenant filter using (_unitOfWorkManager.Current.SetTenantId(tenant.Id)) { //Create static roles for new tenant CheckErrors(await _roleManager.CreateStaticRoles(tenant.Id)); await _unitOfWorkManager.Current.SaveChangesAsync(); //To get static role ids //grant all permissions to admin role var adminRole = _roleManager.Roles.Single(r => r.Name == StaticRoleNames.Tenants.Admin); await _roleManager.GrantAllPermissionsAsync(adminRole); //User role should be default var userRole = _roleManager.Roles.Single(r => r.Name == StaticRoleNames.Tenants.User); userRole.IsDefault = true; CheckErrors(await _roleManager.UpdateAsync(userRole)); //Create admin user for the tenant if (adminPassword.IsNullOrEmpty()) { adminPassword = User.CreateRandomPassword(); } var adminUser = User.CreateTenantAdminUser(tenant.Id, adminEmailAddress, adminPassword); adminUser.ShouldChangePasswordOnNextLogin = shouldChangePasswordOnNextLogin; adminUser.IsActive = isActive; CheckErrors(await _userManager.CreateAsync(adminUser)); await _unitOfWorkManager.Current.SaveChangesAsync(); //To get admin user's id //Assign admin user to admin role! CheckErrors(await _userManager.AddToRoleAsync(adminUser.Id, adminRole.Name)); //Notifications await _appNotifier.WelcomeToTheApplicationAsync(adminUser); //Send activation email if (sendActivationEmail) { adminUser.SetNewEmailConfirmationCode(); await _userEmailer.SendEmailActivationLinkAsync(adminUser, adminPassword); } await _unitOfWorkManager.Current.SaveChangesAsync(); await _demoDataBuilder.BuildForAsync(tenant); newTenantId = tenant.Id; newAdminId = adminUser.Id; } if (sourcetenantId.HasValue) await CloneTenantData(newTenantId, sourcetenantId, entityList); await uow.CompleteAsync(); } //Used a second UOW since UOW above sets some permissions and _notificationSubscriptionManager.SubscribeToAllAvailableNotificationsAsync needs these permissions to be saved. using (var uow = _unitOfWorkManager.Begin(TransactionScopeOption.RequiresNew)) { using (_unitOfWorkManager.Current.SetTenantId(newTenantId)) { await _notificationSubscriptionManager.SubscribeToAllAvailableNotificationsAsync(new UserIdentifier(newTenantId, newAdminId)); await _unitOfWorkManager.Current.SaveChangesAsync(); await uow.CompleteAsync(); } } return newTenantId; }
Do you find any issue with this code ?
-
0
Hi,
Can you try to move added codes in a seperate unitOfWork ?
Move these lines before first unitOfWork and put it inside another unit of work
var connectionstringUnit = await (from org in _organizationRepository.GetAll() join constr in _connectionStringRepository.GetAll() on org.ConnectionStringId equals constr.Id where org.Id == organizationId select constr).FirstOrDefaultAsync();
and put CloneTenantData just before these lines and put it in a new unitOfWork
//Used a second UOW since UOW above sets some permissions and _notificationSubscriptionManager.SubscribeToAllAvailableNotificationsAsync needs these permissions to be saved. using (var uow = _unitOfWorkManager.Begin(TransactionScopeOption.RequiresNew))
Can you also share CloneTenantData code if this does not work for you ?
Thanks.