Из вашего вопроса я понимаю, что вы находитесь в процессе включения модели базы данных арендатора для создаваемого приложения. в этом случае у вас должна быть фабрика, которая выполняет следующее
- Разрешение клиента (по URL или на основе любых других входных параметров)
- У вас есть менеджер сегментов, который ищет строку подключения по идентификатору арендатора и затем использует ее для связи с нужной базой данных для арендатора.
Короче, у вас должно быть что-то вроде того, что ниже
public interface ITenantShardResolver
{
/// <summary>
/// Gets the tenant specific shard based connection from the metadata
/// </summary>
/// <param name="tenantId">The tenant identifier</param>
/// <param name="connectionStringName">The Connection string name</param>
/// <returns>
/// The DbConnection for the specific shard per tenant
/// <see cref="DbConnection"/>
/// </returns>
DbConnection GetConnection(Guid tenantId, string connectionStringName);
}
Выше приведен общий интерфейс, который можно использовать для получения строк подключения на основе установленного контекста клиента.
Базовый контекст базы данных будет выглядеть примерно так, как показано ниже,
public abstract class EntitiesContext : DbContext, IEntitiesContext
{
/// <summary>
/// Constructs a new context instance using conventions to create the name of
/// the database to which a connection will be made. The by-convention name is
/// the full name (namespace + class name) of the derived context class. See
/// the class remarks for how this is used to create a connection.
/// </summary>
protected EntitiesContext() : base()
{
}
/// <summary>
/// Initializes the entity context based on the established user context and the tenant shard map resolver
/// </summary>
/// <param name="userContext">The user context</param>
/// <param name="shardResolver">The Tenant Shard map resolver</param>
/// <param name="nameorConnectionString">The name or the connection string for the entity</param>
protected EntitiesContext(MultiTenancy.Core.ProviderContracts.IUserContextDataProvider userContext, ITenantShardResolver shardResolver, string nameorConnectionString)
: base(shardResolver.GetConnection(userContext.TenantId, nameorConnectionString), true)
{
}
}
Пример контекста будет выглядеть так, как показано ниже,
public class AccommodationEntities : EntitiesContext
{
public AccommodationEntities(IUserContextDataProvider userContextProvider, ITenantShardResolver shardResolver)
: base(userContextProvider, shardResolver, "AccommodationEntities")
{ }
// NOTE: You have the same constructors as the DbContext here. E.g:
public AccommodationEntities() : base("AccommodationEntities") { }
public IDbSet<Country> Countries { get; set; }
public IDbSet<Resort> Resorts { get; set; }
public IDbSet<Hotel> Hotels { get; set; }
}
Базовый сервис, который может взаимодействовать с вышеуказанным контекстом, будет выглядеть так, как показано ниже
public abstract class MultiTenantServices<TEntity, TId>
where TEntity : class, IMultiTenantEntity<TId>
where TId : IComparable
{
private readonly IMultiTenantRepository<TEntity, TId> _repository;
/// <summary>
/// Initializes a new instance of the <see cref="MultiTenantServices{TEntity, TId}"/> class.
/// </summary>
/// <param name="repository">The repository.</param>
protected MultiTenantServices(IMultiTenantRepository<TEntity, TId> repository)
{
_repository = repository;
}
С примером службы сущностей, похожей на приведенную ниже,
public class CountryService : MultiTenantServices<Country, int>
{
IMultiTenantRepository<Country, int> _repository = null;
public CountryService(IMultiTenantRepository<Country, int> repository) : base(repository)
{
_repository = repository;
}
Приведенные выше фрагменты кода иллюстрируют хорошо протестированный и хороший способ организации / разработки приложения для мультитенантности.
НТН