Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changing SQL Server DB Schema at runtime (#802) #1814

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion data/Piranha.Data.EF/Db.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
*/

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage;
using System;
using System.Linq;

Expand Down Expand Up @@ -222,12 +224,26 @@ public abstract class Db<T> : DbContext, IDb where T : Db<T>
/// </summary>
public DbSet<Data.Taxonomy> Taxonomies { get; set; }

/// <summary>
/// Gets the default database schema.
/// </summary>
/// <remarks>
/// If null, the database schema will fall back to the default value used by the database connection.
/// </remarks>
protected string DatabaseSchema { get; }

/// <summary>
/// Default constructor.
/// </summary>
/// <param name="options">Configuration options</param>
public Db(DbContextOptions<T> options) : base(options)
{
var schemaExtension = options.FindExtension<PiranhaEFDatabaseSchemaExtension>();
if (schemaExtension != null)
{
DatabaseSchema = schemaExtension.Schema;
}

if (!IsInitialized)
{
lock (Mutex)
Expand All @@ -251,6 +267,11 @@ public Db(DbContextOptions<T> options) : base(options)
/// <param name="mb">The current model builder</param>
protected override void OnModelCreating(ModelBuilder mb)
{
if (DatabaseSchema is not null)
{
mb.HasDefaultSchema(DatabaseSchema);
}

mb.Entity<Data.Alias>().ToTable("Piranha_Aliases");
mb.Entity<Data.Alias>().Property(a => a.AliasUrl).IsRequired().HasMaxLength(256);
mb.Entity<Data.Alias>().Property(a => a.RedirectUrl).IsRequired().HasMaxLength(256);
Expand Down Expand Up @@ -434,7 +455,6 @@ protected override void OnModelCreating(ModelBuilder mb)
mb.Entity<Data.Site>().HasOne(s => s.Language).WithMany().OnDelete(DeleteBehavior.Restrict);
mb.Entity<Data.Site>().HasIndex(s => s.InternalId).IsUnique();


mb.Entity<Data.SiteField>().ToTable("Piranha_SiteFields");
mb.Entity<Data.SiteField>().Property(f => f.RegionId).HasMaxLength(64).IsRequired();
mb.Entity<Data.SiteField>().Property(f => f.FieldId).HasMaxLength(64).IsRequired();
Expand Down
79 changes: 79 additions & 0 deletions data/Piranha.Data.EF/PiranhaEFDatabaseSchemaExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright (c) .NET Foundation and Contributors
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*
* https://github.com/piranhacms/piranha.core
*
*/

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
/// <summary>
/// A database context extension used to store a custom database schema.
/// The schema set will be used as the default schema in the database context that this extension is configured.
/// Used by the <see cref="PiranhaEFExtensions.UseCustomDatabaseSchema(DbContextOptionsBuilder, string)"/> extension method.
/// </summary>
/// <inheritdoc />
internal class PiranhaEFDatabaseSchemaExtension : IDbContextOptionsExtension
{
public PiranhaEFDatabaseSchemaExtension(string schema) => SetSchema(schema);

/// <summary>
/// Sets the schema.
/// </summary>
/// <param name="schema">The schema to use.</param>
/// <exception cref="ArgumentException">When schema is null or an empty string.</exception>
public void SetSchema(string schema)
{
if (string.IsNullOrWhiteSpace(schema))
{
throw new ArgumentException("Schema must be a non-empty string", nameof(schema));
}
Schema = schema;
}

private PiranhaEFDarabaseSchemaExtensionInfo _info;

public DbContextOptionsExtensionInfo Info => _info ??= new PiranhaEFDarabaseSchemaExtensionInfo(this);

public string Schema { get; private set; }

public void ApplyServices(IServiceCollection services)
{
// This extension does not apply any additional services
}

public void Validate(IDbContextOptions options)
{
// This extension does not participate in options validation
}
}

/// <summary>
/// The database schema extension info.
/// Used by <see cref="PiranhaEFDatabaseSchemaExtension"/> extension.
/// </summary>
/// <inheritdoc />
internal class PiranhaEFDarabaseSchemaExtensionInfo : DbContextOptionsExtensionInfo
{
public PiranhaEFDarabaseSchemaExtensionInfo(IDbContextOptionsExtension extension) : base(extension)
{
}

public override string LogFragment { get; } = string.Empty;
public override bool IsDatabaseProvider { get; }

public override int GetServiceProviderHashCode() => 0;

public override void PopulateDebugInfo(IDictionary<string, string> debugInfo)
{
// This extension does not provide additional debug info
}

public override bool ShouldUseSameServiceProvider(DbContextOptionsExtensionInfo other) => true;
}
31 changes: 31 additions & 0 deletions data/Piranha.Data.EF/PiranhaEFExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,18 @@
*/

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Migrations.Internal;
using Microsoft.Extensions.DependencyInjection;
using Piranha;
using Piranha.Repositories;
using Piranha.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

public static class PiranhaEFExtensions
{
Expand Down Expand Up @@ -92,4 +99,28 @@ private static IServiceCollection RegisterServices<T>(this IServiceCollection se

return services;
}

/// <summary>
/// Adds a custom database schema that will be used by the database context being configured.
/// </summary>
/// <param name="builder">The database context options builder.</param>
/// <param name="schema">The database schema.</param>
/// <returns>A database context options builder.</returns>
/// <exception cref="ArgumentException">Throws when <paramref name="schema"/> is null or empty.</exception>
public static DbContextOptionsBuilder UseCustomDatabaseSchema(this DbContextOptionsBuilder builder, string schema)
{
var extension = builder.Options.FindExtension<PiranhaEFDatabaseSchemaExtension>();
if (extension == null)
{
extension = new PiranhaEFDatabaseSchemaExtension(schema);
}
else
{
extension.SetSchema(schema);
}

((IDbContextOptionsBuilderInfrastructure)builder).AddOrUpdateExtension(extension);

return builder;
}
}