#asp.net-core #entity-framework-core #aspnetboilerplate #boilerplate
Вопрос:
Я создаю веб-приложение с шаблоном AspNetBoilerplate. Основная DbContext
уже настроена и работает правильно, но мне также нужно подключиться ко второй базе данных, чтобы запустить некоторые хранимые процедуры.
Мне удалось создать, внедрить и использовать это DbContext
, но когда я выполнить хранимую процедуру, транзакция «зависает», и я не могу получить доступ к таблицам, что хранимая процедура влияет, пока приложение не остановится (когда служба завершает выполнение метода), а также вставок и обновлений из хранимой процедуры не помогут.
Я создал все это на основе этих ссылок: https://aspnetboilerplate.com/Pages/Documents/Articles/Using-Stored-Procedures,-User-Defined-Functions-and-Views/index.html
https://github.com/aspnetboilerplate/aspnetboilerplate-samples/tree/master/MultipleDbContextEfCoreDemo
Это код, касающийся второго DbContext
:
public class OperacionesRbDbContext : AbpDbContext
{
public OperacionesRbDbContext(DbContextOptions<OperacionesRbDbContext> options)
: base(options)
{
}
}
Репозиторий, выполняющий хранимую процедуру:
public class PersonaRepository : OperacionesRbRepositoryBase<Persona, int>, IPersonaRepository
{
public ILogger Logger { get; set; }
private readonly IActiveTransactionProvider _transactionProvider;
public PersonaRepository(IDbContextProvider<OperacionesRbDbContext> dbContextProvider, IActiveTransactionProvider transactionProvider)
: base(dbContextProvider)
{
_transactionProvider = transactionProvider;
Logger = NullLogger.Instance;
}
public async Task<int> AltaEmpleado(Persona persona)
{
await EnsureConnectionOpenAsync();
SqlParameter[] sqlParameters = CrearParametros(persona);
using (var command = CreateCommand("SP_insert", CommandType.StoredProcedure, sqlParameters))
{
int result = 0;
using (var dataReader = await command.ExecuteReaderAsync())
{
while (dataReader.Read())
{
result = (int)dataReader["@RETURN"];
}
}
return resu<
}
}
private DbCommand CreateCommand(string commandText, CommandType commandType, params SqlParameter[] parameters)
{
var command = Context.Database.GetDbConnection().CreateCommand();
command.CommandText = commandText;
command.CommandType = commandType;
command.Transaction = GetActiveTransaction();
foreach (var parameter in parameters)
{
command.Parameters.Add(parameter);
}
return command;
}
private async Task EnsureConnectionOpenAsync()
{
var connection = Context.Database.GetDbConnection();
if (connection.State != ConnectionState.Open)
{
await connection.OpenAsync();
}
}
private DbTransaction GetActiveTransaction()
{
return (DbTransaction)_transactionProvider.GetActiveTransaction(new ActiveTransactionProviderArgs
{
{"ContextType", typeof(OperacionesRbDbContext) },
{"MultiTenancySide", MultiTenancySide }
});
}
}
Entity Framework module of my application initializing both contexts:
[DependsOn(
typeof(ABTransitCoreModule),
typeof(AbpZeroCoreEntityFrameworkCoreModule))]
public class ABTransitEntityFrameworkModule : AbpModule
{
/* Used it tests to skip dbcontext registration, in order to use in-memory database of EF Core */
public bool SkipDbContextRegistration { get; set; }
public bool SkipDbSeed { get; set; }
public override void PreInitialize()
{
Configuration.ReplaceService<IConnectionStringResolver, OperacionesRbStringResolver>();
Configuration.Modules.AbpEfCore().AddDbContext<ABTransitDbContext>(options =>
{
if (options.ExistingConnection != null)
{
ABTransitDbContextConfigurer.Configure(options.DbContextOptions, options.ExistingConnection);
}
else
{
ABTransitDbContextConfigurer.Configure(options.DbContextOptions, options.ConnectionString);
}
});
Configuration.Modules.AbpEfCore().AddDbContext<OperacionesRbDbContext>(options =>
{
if (options.ExistingConnection != null)
{
OperacionesRbDbContextConfigurer.Configure(options.DbContextOptions, options.ExistingConnection);
}
else
{
OperacionesRbDbContextConfigurer.Configure(options.DbContextOptions, options.ConnectionString);
}
});
}
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(typeof(ABTransitEntityFrameworkModule).GetAssembly());
}
public override void PostInitialize()
{
if (!SkipDbSeed)
{
SeedHelper.SeedHostDb(IocManager);
}
}
}
String resolver:
public class OperacionesRbStringResolver : DefaultConnectionStringResolver
{
private readonly IConfigurationRoot _appConfiguration;
public OperacionesRbStringResolver(IAbpStartupConfiguration configuration, IHostingEnvironment hostingEnvironment)
: base(configuration)
{
_appConfiguration =
AppConfigurations.Get(hostingEnvironment.ContentRootPath, hostingEnvironment.EnvironmentName);
}
public override string GetNameOrConnectionString(ConnectionStringResolveArgs args)
{
if (args["DbContextConcreteType"] as Type == typeof(OperacionesRbDbContext))
{
var configuration = AppConfigurations.Get(WebContentDirectoryFinder.CalculateContentRootFolder());
return configuration.GetConnectionString(OperacionesRbConsts.ConnectionStringName);
}
return base.GetNameOrConnectionString(args);
}
}
There’s also the ContextFactory
and ContextConfigurer
for the second DbContext
, but I don’t want to flood the post with code.
Кажется, я не могу найти документацию по выполнению хранимых процедур, которые вставляют и обновляют записи, только для операторов SELECT, и я все еще новичок в шаблонах и ядре EF. Кто-нибудь может мне в этом помочь?
Заранее спасибо.