Skip to content

Commit

Permalink
Merge pull request #7619 from abpframework/module-db-group
Browse files Browse the repository at this point in the history
Define and handle AbpDbConnectionOptions.Databases option.
  • Loading branch information
hikalkan authored Feb 8, 2021
2 parents 16d3563 + 005bf4b commit 4bf04bb
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 29 deletions.
9 changes: 9 additions & 0 deletions framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDataModule.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.Modularity;
using Volo.Abp.ObjectExtending;
using Volo.Abp.Uow;
Expand All @@ -27,6 +28,14 @@ public override void ConfigureServices(ServiceConfigurationContext context)
context.Services.AddSingleton(typeof(IDataFilter<>), typeof(DataFilter<>));
}

public override void PostConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpDbConnectionOptions>(options =>
{
options.Databases.RefreshIndexes();
});
}

private static void AutoAddDataSeedContributors(IServiceCollection services)
{
var contributors = new List<Type>();
Expand Down
28 changes: 28 additions & 0 deletions framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDatabaseInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.Collections.Generic;

namespace Volo.Abp.Data
{
public class AbpDatabaseInfo
{
public string DatabaseName { get; set; }

/// <summary>
/// List of connection names mapped to this database.
/// </summary>
public HashSet<string> MappedConnections { get; }

/// <summary>
/// Is this database used by tenants. Set this to true if this database
/// can't owned by tenants.
///
/// Default: true.
/// </summary>
public bool IsUsedByTenants { get; set; } = true;

internal AbpDatabaseInfo(string databaseName)
{
DatabaseName = databaseName;
MappedConnections = new HashSet<string>();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;

namespace Volo.Abp.Data
{
public class AbpDatabaseInfoDictionary : Dictionary<string, AbpDatabaseInfo>
{
private Dictionary<string, AbpDatabaseInfo> ConnectionIndex { get; set; }

public AbpDatabaseInfoDictionary()
{
ConnectionIndex = new Dictionary<string, AbpDatabaseInfo>();
}

[CanBeNull]
public AbpDatabaseInfo GetMappedDatabaseOrNull(string connectionStringName)
{
return ConnectionIndex.GetOrDefault(connectionStringName);
}

public AbpDatabaseInfoDictionary Configure(string databaseName, Action<AbpDatabaseInfo> configureAction)
{
var databaseInfo = this.GetOrAdd(
databaseName,
() => new AbpDatabaseInfo(databaseName)
);

configureAction(databaseInfo);

return this;
}

/// <summary>
/// This method should be called if this dictionary changes.
/// It refreshes indexes for quick access to the connection informations.
/// </summary>
public void RefreshIndexes()
{
ConnectionIndex = new Dictionary<string, AbpDatabaseInfo>();

foreach (var databaseInfo in Values)
{
foreach (var mappedConnection in databaseInfo.MappedConnections)
{
if (ConnectionIndex.ContainsKey(mappedConnection))
{
throw new AbpException(
$"A connection name can not map to multiple databases: {mappedConnection}."
);
}

ConnectionIndex[mappedConnection] = databaseInfo;
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,54 @@
namespace Volo.Abp.Data
using System;
using System.Collections.Generic;

namespace Volo.Abp.Data
{
public class AbpDbConnectionOptions
{
public ConnectionStrings ConnectionStrings { get; set; }

public AbpDatabaseInfoDictionary Databases { get; set; }

public AbpDbConnectionOptions()
{
ConnectionStrings = new ConnectionStrings();
Databases = new AbpDatabaseInfoDictionary();
}

public string GetConnectionStringOrNull(
string connectionStringName,
bool fallbackToDatabaseMappings = true,
bool fallbackToDefault = true)
{
var connectionString = ConnectionStrings.GetOrDefault(connectionStringName);
if (!connectionString.IsNullOrEmpty())
{
return connectionString;
}

if (fallbackToDatabaseMappings)
{
var database = Databases.GetMappedDatabaseOrNull(connectionStringName);
if (database != null)
{
connectionString = ConnectionStrings.GetOrDefault(database.DatabaseName);
if (!connectionString.IsNullOrEmpty())
{
return connectionString;
}
}
}

if (fallbackToDefault)
{
connectionString = ConnectionStrings.Default;
if (!connectionString.IsNullOrWhiteSpace())
{
return connectionString;
}
}

return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
Expand All @@ -10,7 +9,8 @@ public class DefaultConnectionStringResolver : IConnectionStringResolver, ITrans
{
protected AbpDbConnectionOptions Options { get; }

public DefaultConnectionStringResolver(IOptionsSnapshot<AbpDbConnectionOptions> options)
public DefaultConnectionStringResolver(
IOptionsSnapshot<AbpDbConnectionOptions> options)
{
Options = options.Value;
}
Expand All @@ -28,18 +28,19 @@ public virtual Task<string> ResolveAsync(string connectionStringName = null)

private string ResolveInternal(string connectionStringName)
{
//Get module specific value if provided
if (!connectionStringName.IsNullOrEmpty())
if (connectionStringName == null)
{
var moduleConnString = Options.ConnectionStrings.GetOrDefault(connectionStringName);
if (!moduleConnString.IsNullOrEmpty())
{
return moduleConnString;
}
return Options.ConnectionStrings.Default;
}

var connectionString = Options.GetConnectionStringOrNull(connectionStringName);

if (!connectionString.IsNullOrEmpty())
{
return connectionString;
}

//Get default value
return Options.ConnectionStrings.Default;
return null;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public override async Task<string> ResolveAsync(string connectionStringName = nu
}

var tenantDefaultConnectionString = tenant.ConnectionStrings.Default;

//Requesting default connection string...
if (connectionStringName == null ||
connectionStringName == ConnectionStrings.DefaultConnectionStringName)
Expand All @@ -59,28 +59,26 @@ public override async Task<string> ResolveAsync(string connectionStringName = nu
//Found for the tenant
return connString;
}

//Fallback to the mapped database for the specific connection string
var database = Options.Databases.GetMappedDatabaseOrNull(connectionStringName);
if (database != null)
{
connString = tenant.ConnectionStrings.GetOrDefault(database.DatabaseName);
if (!connString.IsNullOrWhiteSpace())
{
//Found for the tenant
return connString;
}
}

//Fallback to tenant's default connection string if available
if (!tenantDefaultConnectionString.IsNullOrWhiteSpace())
{
return tenantDefaultConnectionString;
}

//Try to find the specific connection string for given name
var connStringInOptions = Options.ConnectionStrings.GetOrDefault(connectionStringName);
if (!connStringInOptions.IsNullOrWhiteSpace())
{
return connStringInOptions;
}

//Fallback to the global default connection string
var defaultConnectionString = Options.ConnectionStrings.Default;
if (!defaultConnectionString.IsNullOrWhiteSpace())
{
return defaultConnectionString;
}

throw new AbpException("No connection string defined!");
return await base.ResolveAsync(connectionStringName);
}

[Obsolete("Use ResolveAsync method.")]
Expand Down

0 comments on commit 4bf04bb

Please sign in to comment.