Browse Source

implemented conn string per database name.

pull/81/head
Halil İbrahim Kalkan 10 years ago
parent
commit
4b7a4ab7d2
  1. 6
      src/AbpDesk/AbpDesk.ConsoleDemo/appsettings.json
  2. 6
      src/AbpDesk/AbpDesk.Web.Mvc/appsettings.json
  3. 10
      src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/AbpDbContextConfigurationContext.cs
  4. 4
      src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/DbContextOptionsFactory.cs
  5. 5
      src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs
  6. 15
      src/Volo.Abp/Volo/Abp/Data/ConnectionStringsDictionary.cs
  7. 16
      src/Volo.Abp/Volo/Abp/Data/ConnectionStringsOption.cs
  8. 33
      src/Volo.Abp/Volo/Abp/Data/DatabaseNameAttribute.cs
  9. 4
      src/Volo.Abp/Volo/Abp/Data/DbConnectionOptions.cs
  10. 6
      src/Volo.Abp/Volo/Abp/Data/DefaultConnectionStringResolver.cs
  11. 2
      src/Volo.Abp/Volo/Abp/Data/IConnectionStringResolver.cs
  12. 10
      src/Volo.Abp/Volo/Abp/Data/IConnectionStringResolverExtensions.cs
  13. 2
      src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkManager.cs
  14. 53
      test/Volo.Abp.Tests/Volo/Abp/Data/ConnectionStringResolver_Tests.cs

6
src/AbpDesk/AbpDesk.ConsoleDemo/appsettings.json

@ -1,9 +1,5 @@
{
"ConnectionStrings": {
"Default": "Server=localhost;Database=AbpDesk;Trusted_Connection=True;",
"Modules": {
"Module1": "Module1-ConnString", //TODO: Remove this dummy definitions
"Module2": "Module2-ConnString"
}
"Default": "Server=localhost;Database=AbpDesk;Trusted_Connection=True;"
}
}

6
src/AbpDesk/AbpDesk.Web.Mvc/appsettings.json

@ -1,9 +1,5 @@
{
"ConnectionStrings": {
"Default": "Server=localhost;Database=AbpDesk;Trusted_Connection=True;",
"Modules": {
"Module1": "Module1-ConnString", //TODO: Remove this dummy definitions
"Module2": "Module2-ConnString"
}
"Default": "Server=localhost;Database=AbpDesk;Trusted_Connection=True;"
}
}

10
src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/AbpDbContextConfigurationContext.cs

@ -8,14 +8,14 @@ namespace Microsoft.Extensions.DependencyInjection
{
public string ConnectionString { get; }
public string ModuleName { get; } //TODO: Use a SchemaName/DatabaseName instead?
public string DatabaseName { get; }
public DbContextOptionsBuilder DbContextOptions { get; protected set; }
public AbpDbContextConfigurationContext(string connectionString, [CanBeNull] string moduleName)
public AbpDbContextConfigurationContext(string connectionString, [CanBeNull] string databaseName)
{
ConnectionString = connectionString;
ModuleName = moduleName;
DatabaseName = databaseName;
DbContextOptions = new DbContextOptionsBuilder();
}
}
@ -25,8 +25,8 @@ namespace Microsoft.Extensions.DependencyInjection
{
public new DbContextOptionsBuilder<TDbContext> DbContextOptions => (DbContextOptionsBuilder<TDbContext>)base.DbContextOptions;
public AbpDbContextConfigurationContext(string connectionString, [CanBeNull] string moduleName)
: base(connectionString, moduleName)
public AbpDbContextConfigurationContext(string connectionString, [CanBeNull] string databaseName)
: base(connectionString, databaseName)
{
base.DbContextOptions = new DbContextOptionsBuilder<TDbContext>();
}

4
src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/DbContextOptionsFactory.cs

@ -13,13 +13,13 @@ namespace Microsoft.Extensions.DependencyInjection
public static DbContextOptions<TDbContext> Create<TDbContext>(IServiceProvider serviceProvider)
where TDbContext : AbpDbContext<TDbContext>
{
const string moduleName = ""; //TODO: Use AbpModuleDescriptor instead of module name?
var databaseName = DatabaseNameAttribute.GetDatabaseName<TDbContext>();
using (var scope = serviceProvider.CreateScope())
{
var connInfoResolver = scope.ServiceProvider.GetRequiredService<IConnectionStringResolver>();
var context = new AbpDbContextConfigurationContext<TDbContext>(connInfoResolver.Resolve(moduleName), moduleName);
var context = new AbpDbContextConfigurationContext<TDbContext>(connInfoResolver.Resolve(databaseName), databaseName);
var dbContextOptions = scope.ServiceProvider.GetRequiredService<IOptions<AbpDbContextOptions>>().Value;

5
src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Uow/EntityFrameworkCore/UnitOfWorkDbContextProvider.cs

@ -26,9 +26,10 @@ namespace Volo.Abp.Uow.EntityFrameworkCore
throw new AbpException("A DbContext can only be created inside a unit of work!");
}
var moduleName = "";//TODO: Get module name from DbContext?
var dbContextKey = $"{moduleName}_{typeof(TDbContext).FullName}_{_connectionStringResolver.Resolve(moduleName)}";
var connectionString = _connectionStringResolver.Resolve<TDbContext>();
var dbContextKey = $"{typeof(TDbContext).FullName}_{connectionString}";
//TODO: It would be very good if we could pass the connection string to DbContext options while creating DbContext! Because _connectionStringResolver.Resolve is called twice in current implementation.
var databaseApi = unitOfWork.GetOrAddDatabaseApi(
dbContextKey,
() => new DbContextDatabaseApi<TDbContext>(

15
src/Volo.Abp/Volo/Abp/Data/ConnectionStringsDictionary.cs

@ -0,0 +1,15 @@
using System.Collections.Generic;
namespace Volo.Abp.Data
{
public class ConnectionStringsDictionary : Dictionary<string, string>
{
private const string DefaultConnectionStringName = "Default";
public string Default
{
get { return this[DefaultConnectionStringName]; }
set { this[DefaultConnectionStringName] = value; }
}
}
}

16
src/Volo.Abp/Volo/Abp/Data/ConnectionStringsOption.cs

@ -1,16 +0,0 @@
using System.Collections.Generic;
namespace Volo.Abp.Data
{
public class ConnectionStringsOption
{
public string Default { get; set; }
public Dictionary<string, string> Modules { get; set; }
public ConnectionStringsOption()
{
Modules = new Dictionary<string, string>();
}
}
}

33
src/Volo.Abp/Volo/Abp/Data/DatabaseNameAttribute.cs

@ -0,0 +1,33 @@
using System;
using System.Linq;
using System.Reflection;
namespace Volo.Abp.Data
{
public class DatabaseNameAttribute : Attribute
{
public string Name { get; }
public DatabaseNameAttribute(string name)
{
Name = name;
}
public static string GetDatabaseName<T>()
{
return GetDatabaseName(typeof(T));
}
public static string GetDatabaseName(Type type)
{
var typeInfo = type.GetTypeInfo();
var databaseNameAttribute = typeInfo.GetCustomAttributes<DatabaseNameAttribute>().FirstOrDefault();
if (databaseNameAttribute != null)
{
return databaseNameAttribute.Name;
}
return type.FullName;
}
}
}

4
src/Volo.Abp/Volo/Abp/Data/DbConnectionOptions.cs

@ -2,11 +2,11 @@
{
public class DbConnectionOptions
{
public ConnectionStringsOption ConnectionStrings { get; set; }
public ConnectionStringsDictionary ConnectionStrings { get; set; }
public DbConnectionOptions()
{
ConnectionStrings = new ConnectionStringsOption();
ConnectionStrings = new ConnectionStringsDictionary();
}
}
}

6
src/Volo.Abp/Volo/Abp/Data/DefaultConnectionStringResolver.cs

@ -14,15 +14,15 @@ namespace Volo.Abp.Data
_options = options.Value;
}
public string Resolve(string modulename)
public string Resolve(string databaseName = null)
{
//Get default value
var connString = _options.ConnectionStrings.Default;
//Override by module specific value if provided
if (!modulename.IsNullOrEmpty())
if (!databaseName.IsNullOrEmpty())
{
var moduleConnString = _options.ConnectionStrings.Modules.GetOrDefault(modulename);
var moduleConnString = _options.ConnectionStrings.GetOrDefault(databaseName);
if (!moduleConnString.IsNullOrEmpty())
{
connString = moduleConnString;

2
src/Volo.Abp/Volo/Abp/Data/IConnectionStringResolver.cs

@ -2,6 +2,6 @@
{
public interface IConnectionStringResolver
{
string Resolve(string modulename);
string Resolve(string databaseName = null);
}
}

10
src/Volo.Abp/Volo/Abp/Data/IConnectionStringResolverExtensions.cs

@ -0,0 +1,10 @@
namespace Volo.Abp.Data
{
public static class ConnectionStringResolverExtensions
{
public static string Resolve<T>(this IConnectionStringResolver resolver)
{
return resolver.Resolve(DatabaseNameAttribute.GetDatabaseName<T>());
}
}
}

2
src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkManager.cs

@ -36,7 +36,7 @@ namespace Volo.Abp.Uow
scope
);
}
catch(Exception ex)
catch
{
scope.Dispose();
throw;

53
test/Volo.Abp.Tests/Volo/Abp/Data/ConnectionStringResolver_Tests.cs

@ -0,0 +1,53 @@
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.Modularity;
using Volo.Abp.TestBase;
using Xunit;
namespace Volo.Abp.Data
{
public class ConnectionStringResolver_Tests : AbpIntegratedTest<ConnectionStringResolver_Tests.TestModule>
{
private const string DefaultConnString = "default-value";
private const string Database1Name = "Database1";
private const string Database1ConnString = "database-1-value";
private const string Database2Name = "Database2";
private readonly IConnectionStringResolver _connectionStringResolver;
public ConnectionStringResolver_Tests()
{
_connectionStringResolver = ServiceProvider.GetRequiredService<IConnectionStringResolver>();
}
[Fact]
public void Should_Get_Default_ConnString_By_Default()
{
_connectionStringResolver.Resolve().ShouldBe(DefaultConnString);
}
[Fact]
public void Should_Get_Specific_ConnString_IfDefined()
{
_connectionStringResolver.Resolve(Database1Name).ShouldBe(Database1ConnString);
}
[Fact]
public void Should_Get_Default_ConnString_If_Not_Specified()
{
_connectionStringResolver.Resolve(Database2Name).ShouldBe(DefaultConnString);
}
public class TestModule : AbpModule
{
public override void ConfigureServices(IServiceCollection services)
{
services.Configure<DbConnectionOptions>(options =>
{
options.ConnectionStrings.Default = DefaultConnString;
options.ConnectionStrings[Database1Name] = Database1ConnString;
});
}
}
}
}
Loading…
Cancel
Save