Domain Driven Design oriented application framework, meets CRUD needs
Stove is an application framework that wraps and abstracts your needs for easy use. Built with strongly adopted dependency injection principles.
Tool | Supports Multiple Database/Session Control inside one UOW |
---|---|
EntityFramework | :white_check_mark: |
EntityFrameworkCore | :white_check_mark: |
NHibernate | :white_check_mark: |
Dapper | :white_check_mark: |
To work with Dapper, you must use EF & EF Core or NHibernate as primary ORM choice. Dapper shares their transactions to execute its sqls inside of one Unit Of Work scope.
Dapper-EntityFramework, Dapper-NHibernate or Dapper-EntityFrameworkCore works under same transaction and unit of work scope, if any exception appears in domain whole transaction will be rollback, including Dapper's insert/deletes or EF's or NH's.
Stove.Dapper supports Dynamic Filters to filter automatically and default ISoftDelete or other user defined filters.
NHibernate supports multiple database in one UOW scope.
Let's assume that we have two entities which are inherited from EntityStoveSessionContext
does that.
public class PrimaryStoveSessionContext : StoveSessionContext
{
public IStoveSessionSet<Product> Products { get; set; }
}
public class SecondaryStoveSessionContext : StoveSessionContext
{
public IStoveSessionSet<Category> Categories { get; set; }
}
Registration:
builder
.UseStoveNHibernate(nhConfiguration =>
{
nhConfiguration.AddFluentConfigurationFor<PrimaryStoveSessionContext>(() =>
{
return Fluently.Configure()
.Database(SQLiteConfiguration.Standard.InMemory())
.Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly()))
.ExposeConfiguration(cfg => new SchemaExport(cfg).Execute(true, true, false, _connection, Console.Out));
});
nhConfiguration.AddFluentConfigurationFor<SecondaryStoveSessionContext>(() =>
{
return Fluently.Configure()
.Database(SQLiteConfiguration.Standard.InMemory())
.Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly()))
.ExposeConfiguration(cfg => new SchemaExport(cfg).Execute(true, true, false, _connection, Console.Out));
});
return nhConfiguration;
})
After this definition, we have to define which SessionContext uses which connection string for connect to database and creating session factory.
[DependsOn(
typeof(StoveNHibernateBootstrapper)
)]
public class StoveNHibernateTestBootstrapper : StoveBootstrapper
{
public override void PreStart()
{
StoveConfiguration.DefaultNameOrConnectionString = "data source=:memory:";
StoveConfiguration.TypedConnectionStrings.Add(typeof(PrimaryStoveSessionContext),StoveConfiguration.DefaultNameOrConnectionString);
StoveConfiguration.TypedConnectionStrings.Add(typeof(SecondaryStoveSessionContext),StoveConfiguration.DefaultNameOrConnectionString);
DapperExtensions.DapperExtensions.SqlDialect = new SqliteDialect();
DapperExtensions.DapperExtensions.SetMappingAssemblies(new List<Assembly> { Assembly.GetExecutingAssembly() });
}
}
As you see connection strings are same but they are inside of different StoveSessionContexts. If these entities are inside of same database but you want to treat as different bounded contexts to them, you can choose this kind of approach for your sessions. Otherwise entities can sit together in one SessionContext.
Usage is always same and persistence agnostic:
using (IUnitOfWorkCompleteHandle uow = The<IUnitOfWorkManager>().Begin())
{
The<IDapperRepository<Product>>().GetAll().Count().ShouldBe(1);
The<IRepository<Product>>().GetAll().Count().ShouldBe(1);
uow.Complete();
}
IRootResolver resolver = IocBuilder.New
.UseAutofacContainerBuilder()
.UseStove<StoveDemoBootstrapper>(autoUnitOfWorkInterceptionEnabled: true)
.UseStoveEntityFramework()
.UseStoveDapper()
.UseStoveMapster()
.UseStoveDefaultEventBus()
.UseStoveDbContextEfTransactionStrategy()
.UseStoveTypedConnectionStringResolver()
.UseStoveNLog()
.UseStoveBackgroundJobs()
.UseStoveRedisCaching()
.UseStoveRabbitMQ(configuration =>
{
configuration.HostAddress = "rabbitmq://localhost/";
configuration.Username = "admin";
configuration.Password = "admin";
configuration.QueueName = "Default";
return configuration;
})
.UseStoveHangfire(configuration =>
{
configuration.GlobalConfiguration
.UseSqlServerStorage("Default")
.UseNLogLogProvider();
return configuration;
})
.RegisterServices(r => r.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly()))
.CreateResolver();
var someDomainService = resolver.Resolve<SomeDomainService>();
someDomainService.DoSomeStuff();