From 9c97ba17c422755c01c9c68efe08cdfbe1748546 Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Fri, 12 Jan 2024 17:38:48 -0800 Subject: [PATCH] Add back some methods to RuntimeAnnotatableBase Fixes #32739 --- .../Metadata/Internal/RelationalModel.cs | 19 ++-- src/EFCore/Metadata/IReadOnlyEntityType.cs | 2 +- src/EFCore/Metadata/RuntimeAnnotatableBase.cs | 47 ++++++++- src/EFCore/Metadata/RuntimeEntityType.cs | 59 +++++++++-- src/EFCore/Metadata/RuntimeModel.cs | 14 ++- src/EFCore/Metadata/RuntimeTypeBase.cs | 2 +- .../CompiledModelRelationalTestBase.cs | 98 +++++++++++++++++++ .../Scaffolding/CompiledModelTestBase.cs | 13 ++- .../Dynamic_schema/DataEntityType.cs | 94 ++++++++++++++++++ .../Dynamic_schema/DbContextModel.cs | 48 +++++++++ .../Dynamic_schema/DbContextModelBuilder.cs | 82 ++++++++++++++++ .../DbContextModelCustomizer.cs | 72 ++++++++++++++ .../Dynamic_schema/DataEntityType.cs | 91 +++++++++++++++++ .../Dynamic_schema/DbContextModel.cs | 48 +++++++++ .../Dynamic_schema/DbContextModelBuilder.cs | 80 +++++++++++++++ .../DbContextModelCustomizer.cs | 72 ++++++++++++++ 16 files changed, 815 insertions(+), 26 deletions(-) create mode 100644 test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DataEntityType.cs create mode 100644 test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DbContextModel.cs create mode 100644 test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DbContextModelBuilder.cs create mode 100644 test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DbContextModelCustomizer.cs create mode 100644 test/EFCore.Sqlite.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DataEntityType.cs create mode 100644 test/EFCore.Sqlite.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DbContextModel.cs create mode 100644 test/EFCore.Sqlite.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DbContextModelBuilder.cs create mode 100644 test/EFCore.Sqlite.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DbContextModelCustomizer.cs diff --git a/src/EFCore.Relational/Metadata/Internal/RelationalModel.cs b/src/EFCore.Relational/Metadata/Internal/RelationalModel.cs index 6fadc51627c..67dc9221560 100644 --- a/src/EFCore.Relational/Metadata/Internal/RelationalModel.cs +++ b/src/EFCore.Relational/Metadata/Internal/RelationalModel.cs @@ -383,7 +383,7 @@ private static void AddTables( Check.DebugAssert(entityType.FindRuntimeAnnotationValue(RelationalAnnotationNames.TableMappings) == null, "not null"); var tableMappings = new List(); - entityType.SetRuntimeAnnotation(RelationalAnnotationNames.TableMappings, tableMappings); + entityType.AddRuntimeAnnotation(RelationalAnnotationNames.TableMappings, tableMappings); var mappingStrategy = entityType.GetMappingStrategy(); var isTpc = mappingStrategy == RelationalAnnotationNames.TpcMappingStrategy; @@ -500,8 +500,13 @@ private static void CreateTableMapping( foreach (var complexProperty in mappedType.GetDeclaredComplexProperties()) { var complexType = complexProperty.ComplexType; - var complexTableMappings = new List(); - complexType.SetRuntimeAnnotation(RelationalAnnotationNames.TableMappings, complexTableMappings); + + var complexTableMappings = (List?)complexType.FindRuntimeAnnotationValue(RelationalAnnotationNames.TableMappings); + if (complexTableMappings == null) + { + complexTableMappings = []; + complexType.AddRuntimeAnnotation(RelationalAnnotationNames.TableMappings, complexTableMappings); + } CreateTableMapping( relationalTypeMappingSource, @@ -570,7 +575,7 @@ private static void AddViews( Check.DebugAssert(entityType.FindRuntimeAnnotationValue(RelationalAnnotationNames.ViewMappings) == null, "not null"); var viewMappings = new List(); - entityType.SetRuntimeAnnotation(RelationalAnnotationNames.ViewMappings, viewMappings); + entityType.AddRuntimeAnnotation(RelationalAnnotationNames.ViewMappings, viewMappings); var mappingStrategy = entityType.GetMappingStrategy(); var isTpc = mappingStrategy == RelationalAnnotationNames.TpcMappingStrategy; @@ -1061,19 +1066,19 @@ private static void AddStoredProcedures( if (insertStoredProcedureMappings?.Count > 0) { insertStoredProcedureMappings.Reverse(); - entityType.SetRuntimeAnnotation(RelationalAnnotationNames.InsertStoredProcedureMappings, insertStoredProcedureMappings); + entityType.AddRuntimeAnnotation(RelationalAnnotationNames.InsertStoredProcedureMappings, insertStoredProcedureMappings); } if (deleteStoredProcedureMappings?.Count > 0) { deleteStoredProcedureMappings.Reverse(); - entityType.SetRuntimeAnnotation(RelationalAnnotationNames.DeleteStoredProcedureMappings, deleteStoredProcedureMappings); + entityType.AddRuntimeAnnotation(RelationalAnnotationNames.DeleteStoredProcedureMappings, deleteStoredProcedureMappings); } if (updateStoredProcedureMappings?.Count > 0) { updateStoredProcedureMappings.Reverse(); - entityType.SetRuntimeAnnotation(RelationalAnnotationNames.UpdateStoredProcedureMappings, updateStoredProcedureMappings); + entityType.AddRuntimeAnnotation(RelationalAnnotationNames.UpdateStoredProcedureMappings, updateStoredProcedureMappings); } } diff --git a/src/EFCore/Metadata/IReadOnlyEntityType.cs b/src/EFCore/Metadata/IReadOnlyEntityType.cs index 99646c2d79f..b5ee5ba7083 100644 --- a/src/EFCore/Metadata/IReadOnlyEntityType.cs +++ b/src/EFCore/Metadata/IReadOnlyEntityType.cs @@ -262,7 +262,7 @@ bool IsAssignableFrom(IReadOnlyEntityType derivedType) /// The property that the key is defined on. /// The key, or null if none is defined. IReadOnlyKey? FindKey(IReadOnlyProperty property) - => FindKey(new[] { property }); + => FindKey([property]); /// /// Gets the primary and alternate keys for this entity type. diff --git a/src/EFCore/Metadata/RuntimeAnnotatableBase.cs b/src/EFCore/Metadata/RuntimeAnnotatableBase.cs index 260f4cfc02e..cc7d6429d5e 100644 --- a/src/EFCore/Metadata/RuntimeAnnotatableBase.cs +++ b/src/EFCore/Metadata/RuntimeAnnotatableBase.cs @@ -3,7 +3,6 @@ using System.Collections.Concurrent; using Microsoft.EntityFrameworkCore.Internal; -using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace Microsoft.EntityFrameworkCore.Infrastructure; @@ -22,7 +21,7 @@ namespace Microsoft.EntityFrameworkCore.Infrastructure; /// public class RuntimeAnnotatableBase : IAnnotatable { - private readonly Dictionary _annotations = new(StringComparer.Ordinal); + private Dictionary? _annotations; private ConcurrentDictionary? _runtimeAnnotations; /// @@ -104,6 +103,7 @@ public virtual void SetAnnotation(string name, object? value) string name, Annotation annotation) { + _annotations ??= new(StringComparer.Ordinal); _annotations[name] = annotation; return annotation; @@ -120,7 +120,7 @@ public virtual void SetAnnotation(string name, object? value) { Check.NotEmpty(name, nameof(name)); - return _annotations.TryGetValue(name, out var annotation) + return _annotations != null && _annotations.TryGetValue(name, out var annotation) ? annotation : null; } @@ -143,6 +143,26 @@ public virtual Annotation GetAnnotation(string annotationName) return annotation; } + /// + /// Removes the given annotation from this object. + /// + /// The annotation to remove. + /// The annotation that was removed. + public virtual Annotation? RemoveAnnotation(string name) + { + Check.NotNull(name, nameof(name)); + + var annotation = FindAnnotation(name); + if (annotation == null) + { + return null; + } + + _annotations!.Remove(name); + + return annotation; + } + /// /// Gets the value annotation with the given name, returning if it does not exist. /// @@ -151,7 +171,24 @@ public virtual Annotation GetAnnotation(string annotationName) /// The value of the existing annotation if an annotation with the specified name already exists. /// Otherwise, . /// - public virtual object? this[string name] => FindAnnotation(name)?.Value; + public virtual object? this[string name] + { + get => FindAnnotation(name)?.Value; + + set + { + Check.NotEmpty(name, nameof(name)); + + if (value == null) + { + RemoveAnnotation(name); + } + else + { + SetAnnotation(name, value); + } + } + } /// /// Creates a new annotation. @@ -330,7 +367,7 @@ private ConcurrentDictionary GetOrCreateRuntimeAnnotations() /// [DebuggerStepThrough] IEnumerable IReadOnlyAnnotatable.GetAnnotations() - => _annotations.Values.OrderBy(a => a.Name, StringComparer.Ordinal); + => _annotations?.Values.OrderBy(a => a.Name, StringComparer.Ordinal) ?? Enumerable.Empty(); /// [DebuggerStepThrough] diff --git a/src/EFCore/Metadata/RuntimeEntityType.cs b/src/EFCore/Metadata/RuntimeEntityType.cs index 3dc3f2ba6b3..415375d4de2 100644 --- a/src/EFCore/Metadata/RuntimeEntityType.cs +++ b/src/EFCore/Metadata/RuntimeEntityType.cs @@ -94,12 +94,12 @@ public RuntimeEntityType( _serviceProperties = new(servicePropertyCount, StringComparer.Ordinal); } _unnamedIndexes = new(unnamedIndexCount, PropertyListComparer.Instance); - if(namedIndexCount > 0) + if (namedIndexCount > 0) { _namedIndexes = new(namedIndexCount, StringComparer.Ordinal); } _keys = new(keyCount, PropertyListComparer.Instance); - if(triggerPropertyCount > 0) + if (triggerPropertyCount > 0) { _triggers = new(triggerPropertyCount, StringComparer.Ordinal); } @@ -168,10 +168,23 @@ public virtual RuntimeKey AddKey(IReadOnlyList properties) ? key : BaseType?.FindKey(properties); - private IEnumerable GetDeclaredKeys() + /// + /// Gets all keys declared on this entity type. + /// + /// + /// This method does not return keys declared on base types. + /// It is useful when iterating over all entity types to avoid processing the same key more than once. + /// Use to also return keys declared on base types. + /// + /// Declared keys. + public virtual IEnumerable GetDeclaredKeys() => _keys.Values; - private IEnumerable GetKeys() + /// + /// Gets the primary and alternate keys for this entity type. + /// + /// The primary and alternate keys. + public virtual IEnumerable GetKeys() => BaseType?.GetKeys().Concat(_keys.Values) ?? _keys.Values; /// @@ -268,12 +281,27 @@ private IEnumerable FindForeignKeys(IReadOnlyList FindDeclaredForeignKey(properties, principalKey, principalEntityType) ?? BaseType?.FindForeignKey(properties, principalKey, principalEntityType); + /// + /// Gets all foreign keys declared on this entity type.. + /// + /// + /// This method does not return foreign keys declared on base types. + /// It is useful when iterating over all entity types to avoid processing the same foreign key more than once. + /// Use to also return foreign keys declared on base types. + /// + /// Declared foreign keys. + public virtual List GetDeclaredForeignKeys() => _foreignKeys; + private IEnumerable GetDerivedForeignKeys() => !HasDirectlyDerivedTypes ? Enumerable.Empty() : GetDerivedTypes().Cast().SelectMany(et => et._foreignKeys); - private IEnumerable GetForeignKeys() + /// + /// Gets the foreign keys defined on this entity type. + /// + /// The foreign keys defined on this entity type. + public virtual IEnumerable GetForeignKeys() => BaseType != null ? _foreignKeys.Count == 0 ? BaseType.GetForeignKeys() @@ -560,7 +588,16 @@ public virtual RuntimeIndex AddIndex( ? index : BaseType?.FindIndex(name); - private IEnumerable GetDeclaredIndexes() + /// + /// Gets all indexes declared on this entity type. + /// + /// + /// This method does not return indexes declared on base types. + /// It is useful when iterating over all entity types to avoid processing the same index more than once. + /// Use to also return indexes declared on base types. + /// + /// Declared indexes. + public virtual IEnumerable GetDeclaredIndexes() => _namedIndexes == null ? _unnamedIndexes.Values : _unnamedIndexes.Values.Concat(_namedIndexes.Values); @@ -570,7 +607,11 @@ private IEnumerable GetDerivedIndexes() ? Enumerable.Empty() : GetDerivedTypes().Cast().SelectMany(et => et.GetDeclaredIndexes()); - private IEnumerable GetIndexes() + /// + /// Gets the indexes defined on this entity type. + /// + /// The indexes defined on this entity type. + public virtual IEnumerable GetIndexes() => BaseType != null ? _namedIndexes == null ? BaseType.GetIndexes() @@ -1057,12 +1098,12 @@ IEnumerable IEntityType.GetForeignKeys() /// [DebuggerStepThrough] IEnumerable IReadOnlyEntityType.GetDeclaredForeignKeys() - => _foreignKeys; + => GetDeclaredForeignKeys(); /// [DebuggerStepThrough] IEnumerable IEntityType.GetDeclaredForeignKeys() - => _foreignKeys; + => GetDeclaredForeignKeys(); /// [DebuggerStepThrough] diff --git a/src/EFCore/Metadata/RuntimeModel.cs b/src/EFCore/Metadata/RuntimeModel.cs index ae84df6a368..d722ac7c309 100644 --- a/src/EFCore/Metadata/RuntimeModel.cs +++ b/src/EFCore/Metadata/RuntimeModel.cs @@ -247,6 +247,16 @@ private IEnumerable FindEntityTypes(Type type) : result; } + /// + /// Gets all entity types defined in the model. + /// + /// + /// See Modeling entity types and relationships for more information and examples. + /// + /// All entity types defined in the model. + private IEnumerable GetEntityTypes() + => _entityTypes.Values.OrderBy(e => e.Name, StringComparer.Ordinal); + /// /// Adds configuration for a scalar type. /// @@ -392,12 +402,12 @@ bool IModel.IsIndexerMethod(MethodInfo methodInfo) /// [DebuggerStepThrough] IEnumerable IReadOnlyModel.GetEntityTypes() - => _entityTypes.Values.OrderBy(e => e.Name, StringComparer.Ordinal); + => GetEntityTypes(); /// [DebuggerStepThrough] IEnumerable IModel.GetEntityTypes() - => _entityTypes.Values.OrderBy(e => e.Name, StringComparer.Ordinal); + => GetEntityTypes(); /// [DebuggerStepThrough] diff --git a/src/EFCore/Metadata/RuntimeTypeBase.cs b/src/EFCore/Metadata/RuntimeTypeBase.cs index 84c96cbb0a6..aea301e943a 100644 --- a/src/EFCore/Metadata/RuntimeTypeBase.cs +++ b/src/EFCore/Metadata/RuntimeTypeBase.cs @@ -258,7 +258,7 @@ public virtual RuntimeProperty AddProperty( => _properties.TryGetValue(name, out var property) ? property : null; - + /// /// Gets all scalar properties declared on this type. /// diff --git a/test/EFCore.Relational.Specification.Tests/Scaffolding/CompiledModelRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Scaffolding/CompiledModelRelationalTestBase.cs index 6a84c1bc5b1..f8d50cdce50 100644 --- a/test/EFCore.Relational.Specification.Tests/Scaffolding/CompiledModelRelationalTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Scaffolding/CompiledModelRelationalTestBase.cs @@ -1176,6 +1176,104 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) } } + [ConditionalFact] + public virtual void Dynamic_schema() + => Test( + modelBuilder => modelBuilder.Entity( + eb => + { + eb.Property("Id"); + eb.HasKey("Id"); + }), + model => + { + Assert.Equal("custom", model.GetDefaultSchema()); + + var dataEntity = model.GetEntityTypes().Single(); + Assert.Equal("custom", dataEntity.GetSchema()); + }, + additionalSourceFiles: + [ + new() + { + Path = "DbContextModelCustomizer.cs", + Code = """ +using Microsoft.EntityFrameworkCore.Metadata; + +namespace TestNamespace; + +public partial class DbContextModel +{ + private string DefaultSchema { get; init; } = "custom"; + + partial void Customize() + { + RemoveAnnotation("Relational:DefaultSchema"); + AddAnnotation("Relational:DefaultSchema", DefaultSchema); + RemoveRuntimeAnnotation("Relational:RelationalModel"); + + foreach (RuntimeEntityType entityType in ((IModel)this).GetEntityTypes()) + { + Customize(entityType); + + foreach (var key in entityType.GetDeclaredKeys()) + { + key.RemoveRuntimeAnnotation(RelationalAnnotationNames.UniqueConstraintMappings); + } + + foreach (var index in entityType.GetDeclaredIndexes()) + { + index.RemoveRuntimeAnnotation(RelationalAnnotationNames.TableIndexMappings); + } + + foreach (var foreignKey in entityType.GetDeclaredForeignKeys()) + { + foreignKey.RemoveRuntimeAnnotation(RelationalAnnotationNames.ForeignKeyMappings); + } + + var tableName = entityType.FindAnnotation("Relational:TableName")?.Value as string; + if (string.IsNullOrEmpty(tableName)) + continue; + + entityType.SetAnnotation("Relational:Schema", DefaultSchema); + } + } + + private static void Customize(RuntimeTypeBase entityType) + { + entityType.RemoveRuntimeAnnotation(RelationalAnnotationNames.DefaultMappings); + entityType.RemoveRuntimeAnnotation(RelationalAnnotationNames.TableMappings); + entityType.RemoveRuntimeAnnotation(RelationalAnnotationNames.ViewMappings); + entityType.RemoveRuntimeAnnotation(RelationalAnnotationNames.SqlQueryMappings); + entityType.RemoveRuntimeAnnotation(RelationalAnnotationNames.FunctionMappings); + entityType.RemoveRuntimeAnnotation(RelationalAnnotationNames.InsertStoredProcedureMappings); + entityType.RemoveRuntimeAnnotation(RelationalAnnotationNames.DeleteStoredProcedureMappings); + entityType.RemoveRuntimeAnnotation(RelationalAnnotationNames.UpdateStoredProcedureMappings); + + foreach (var property in entityType.GetDeclaredProperties()) + { + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.DefaultColumnMappings); + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.TableColumnMappings); + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.ViewColumnMappings); + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.SqlQueryColumnMappings); + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.FunctionColumnMappings); + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.InsertStoredProcedureParameterMappings); + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.DeleteStoredProcedureParameterMappings); + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.UpdateStoredProcedureParameterMappings); + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.InsertStoredProcedureResultColumnMappings); + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.UpdateStoredProcedureResultColumnMappings); + } + + foreach (var complexProperty in entityType.GetDeclaredComplexProperties()) + { + Customize(complexProperty.ComplexType); + } + } +} +""" + } + ]); + public class SpatialTypes : AbstractBase; protected override BuildSource AddReferences(BuildSource build, [CallerFilePath] string filePath = "") diff --git a/test/EFCore.Specification.Tests/Scaffolding/CompiledModelTestBase.cs b/test/EFCore.Specification.Tests/Scaffolding/CompiledModelTestBase.cs index a1f8f8dc616..e06bda7dd35 100644 --- a/test/EFCore.Specification.Tests/Scaffolding/CompiledModelTestBase.cs +++ b/test/EFCore.Specification.Tests/Scaffolding/CompiledModelTestBase.cs @@ -1233,6 +1233,7 @@ protected virtual void Test( CompiledModelCodeGenerationOptions? options = null, Func? addServices = null, Func? addDesignTimeServices = null, + IEnumerable? additionalSourceFiles = null, string? expectedExceptionMessage = null, [CallerMemberName] string testName = "") => Test( @@ -1243,6 +1244,7 @@ protected virtual void Test( options, addServices, addDesignTimeServices, + additionalSourceFiles, expectedExceptionMessage, testName); @@ -1254,6 +1256,7 @@ protected virtual (TContext?, IModel?) Test( CompiledModelCodeGenerationOptions? options = null, Func? addServices = null, Func? addDesignTimeServices = null, + IEnumerable? additionalSourceFiles = null, string? expectedExceptionMessage = null, [CallerMemberName] string testName = "") where TContext : DbContext @@ -1300,10 +1303,18 @@ protected virtual (TContext?, IModel?) Test( model, options); + if (additionalSourceFiles != null) + { + scaffoldedFiles = scaffoldedFiles.Concat(additionalSourceFiles).ToArray(); + } + var compiledModel = CompileModel(scaffoldedFiles, options, context); assertModel?.Invoke(compiledModel); - TestHelpers.ModelAsserter.AssertEqual(context.Model, compiledModel); + if (additionalSourceFiles == null) + { + TestHelpers.ModelAsserter.AssertEqual(context.Model, compiledModel); + } if (useContext != null) { diff --git a/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DataEntityType.cs b/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DataEntityType.cs new file mode 100644 index 00000000000..15190be66ae --- /dev/null +++ b/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DataEntityType.cs @@ -0,0 +1,94 @@ +// +using System; +using System.Collections; +using System.Linq; +using System.Reflection; +using Microsoft.EntityFrameworkCore.ChangeTracking; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Scaffolding; +using Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal; +using Microsoft.EntityFrameworkCore.Storage; + +#pragma warning disable 219, 612, 618 +#nullable disable + +namespace TestNamespace +{ + internal partial class DataEntityType + { + public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType baseEntityType = null) + { + var runtimeEntityType = model.AddEntityType( + "Microsoft.EntityFrameworkCore.Scaffolding.CompiledModelTestBase+Data", + typeof(CompiledModelTestBase.Data), + baseEntityType, + propertyCount: 2, + keyCount: 1); + + var id = runtimeEntityType.AddProperty( + "Id", + typeof(int), + valueGenerated: ValueGenerated.OnAdd, + afterSaveBehavior: PropertySaveBehavior.Throw, + sentinel: 0); + id.TypeMapping = IntTypeMapping.Default.Clone( + comparer: new ValueComparer( + (int v1, int v2) => v1 == v2, + (int v) => v, + (int v) => v), + keyComparer: new ValueComparer( + (int v1, int v2) => v1 == v2, + (int v) => v, + (int v) => v), + providerValueComparer: new ValueComparer( + (int v1, int v2) => v1 == v2, + (int v) => v, + (int v) => v)); + id.AddAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + var blob = runtimeEntityType.AddProperty( + "Blob", + typeof(byte[]), + propertyInfo: typeof(CompiledModelTestBase.Data).GetProperty("Blob", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly), + fieldInfo: typeof(CompiledModelTestBase.Data).GetField("k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly), + nullable: true); + blob.TypeMapping = SqlServerByteArrayTypeMapping.Default.Clone( + comparer: new ValueComparer( + (Byte[] v1, Byte[] v2) => StructuralComparisons.StructuralEqualityComparer.Equals((object)v1, (object)v2), + (Byte[] v) => v.GetHashCode(), + (Byte[] v) => v), + keyComparer: new ValueComparer( + (Byte[] v1, Byte[] v2) => StructuralComparisons.StructuralEqualityComparer.Equals((object)v1, (object)v2), + (Byte[] v) => StructuralComparisons.StructuralEqualityComparer.GetHashCode((object)v), + (Byte[] source) => source.ToArray()), + providerValueComparer: new ValueComparer( + (Byte[] v1, Byte[] v2) => StructuralComparisons.StructuralEqualityComparer.Equals((object)v1, (object)v2), + (Byte[] v) => StructuralComparisons.StructuralEqualityComparer.GetHashCode((object)v), + (Byte[] source) => source.ToArray()), + mappingInfo: new RelationalTypeMappingInfo( + storeTypeName: "varbinary(max)"), + storeTypePostfix: StoreTypePostfix.None); + blob.AddAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.None); + + var key = runtimeEntityType.AddKey( + new[] { id }); + runtimeEntityType.SetPrimaryKey(key); + + return runtimeEntityType; + } + + public static void CreateAnnotations(RuntimeEntityType runtimeEntityType) + { + runtimeEntityType.AddAnnotation("Relational:FunctionName", null); + runtimeEntityType.AddAnnotation("Relational:Schema", null); + runtimeEntityType.AddAnnotation("Relational:SqlQuery", null); + runtimeEntityType.AddAnnotation("Relational:TableName", "Data"); + runtimeEntityType.AddAnnotation("Relational:ViewName", null); + runtimeEntityType.AddAnnotation("Relational:ViewSchema", null); + + Customize(runtimeEntityType); + } + + static partial void Customize(RuntimeEntityType runtimeEntityType); + } +} diff --git a/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DbContextModel.cs b/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DbContextModel.cs new file mode 100644 index 00000000000..583ee4d90cc --- /dev/null +++ b/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DbContextModel.cs @@ -0,0 +1,48 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; + +#pragma warning disable 219, 612, 618 +#nullable disable + +namespace TestNamespace +{ + [DbContext(typeof(DbContext))] + public partial class DbContextModel : RuntimeModel + { + private static readonly bool _useOldBehavior31751 = + System.AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue31751", out var enabled31751) && enabled31751; + + static DbContextModel() + { + var model = new DbContextModel(); + + if (_useOldBehavior31751) + { + model.Initialize(); + } + else + { + var thread = new System.Threading.Thread(RunInitialization, 10 * 1024 * 1024); + thread.Start(); + thread.Join(); + + void RunInitialization() + { + model.Initialize(); + } + } + + model.Customize(); + _instance = (DbContextModel)model.FinalizeModel(); + } + + private static DbContextModel _instance; + public static IModel Instance => _instance; + + partial void Initialize(); + + partial void Customize(); + } +} diff --git a/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DbContextModelBuilder.cs b/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DbContextModelBuilder.cs new file mode 100644 index 00000000000..b62372a6a98 --- /dev/null +++ b/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DbContextModelBuilder.cs @@ -0,0 +1,82 @@ +// +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Metadata.Internal; + +#pragma warning disable 219, 612, 618 +#nullable disable + +namespace TestNamespace +{ + public partial class DbContextModel + { + private DbContextModel() + : base(skipDetectChanges: false, modelId: new Guid("00000000-0000-0000-0000-000000000000"), entityTypeCount: 1) + { + } + + partial void Initialize() + { + var data = DataEntityType.Create(this); + + DataEntityType.CreateAnnotations(data); + + AddAnnotation("Relational:MaxIdentifierLength", 128); + AddAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + AddRuntimeAnnotation("Relational:RelationalModel", CreateRelationalModel()); + } + + private IRelationalModel CreateRelationalModel() + { + var relationalModel = new RelationalModel(this); + + var data = FindEntityType("Microsoft.EntityFrameworkCore.Scaffolding.CompiledModelTestBase+Data")!; + + var defaultTableMappings = new List>(); + data.SetRuntimeAnnotation("Relational:DefaultMappings", defaultTableMappings); + var microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDataTableBase = new TableBase("Microsoft.EntityFrameworkCore.Scaffolding.CompiledModelTestBase+Data", null, relationalModel); + var blobColumnBase = new ColumnBase("Blob", "varbinary(max)", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDataTableBase) + { + IsNullable = true + }; + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDataTableBase.Columns.Add("Blob", blobColumnBase); + var idColumnBase = new ColumnBase("Id", "int", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDataTableBase); + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDataTableBase.Columns.Add("Id", idColumnBase); + relationalModel.DefaultTables.Add("Microsoft.EntityFrameworkCore.Scaffolding.CompiledModelTestBase+Data", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDataTableBase); + var microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDataMappingBase = new TableMappingBase(data, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDataTableBase, null); + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDataTableBase.AddTypeMapping(microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDataMappingBase, false); + defaultTableMappings.Add(microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDataMappingBase); + RelationalModel.CreateColumnMapping((ColumnBase)idColumnBase, data.FindProperty("Id")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDataMappingBase); + RelationalModel.CreateColumnMapping((ColumnBase)blobColumnBase, data.FindProperty("Blob")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDataMappingBase); + + var tableMappings = new List(); + data.SetRuntimeAnnotation("Relational:TableMappings", tableMappings); + var dataTable = new Table("Data", null, relationalModel); + var idColumn = new Column("Id", "int", dataTable); + dataTable.Columns.Add("Id", idColumn); + var blobColumn = new Column("Blob", "varbinary(max)", dataTable) + { + IsNullable = true + }; + dataTable.Columns.Add("Blob", blobColumn); + var pK_Data = new UniqueConstraint("PK_Data", dataTable, new[] { idColumn }); + dataTable.PrimaryKey = pK_Data; + var pK_DataUc = RelationalModel.GetKey(this, + "Microsoft.EntityFrameworkCore.Scaffolding.CompiledModelTestBase+Data", + new[] { "Id" }); + pK_Data.MappedKeys.Add(pK_DataUc); + RelationalModel.GetOrCreateUniqueConstraints(pK_DataUc).Add(pK_Data); + dataTable.UniqueConstraints.Add("PK_Data", pK_Data); + relationalModel.Tables.Add(("Data", null), dataTable); + var dataTableMapping = new TableMapping(data, dataTable, null); + dataTable.AddTypeMapping(dataTableMapping, false); + tableMappings.Add(dataTableMapping); + RelationalModel.CreateColumnMapping(idColumn, data.FindProperty("Id")!, dataTableMapping); + RelationalModel.CreateColumnMapping(blobColumn, data.FindProperty("Blob")!, dataTableMapping); + return relationalModel.MakeReadOnly(); + } + } +} diff --git a/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DbContextModelCustomizer.cs b/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DbContextModelCustomizer.cs new file mode 100644 index 00000000000..8d477de97cb --- /dev/null +++ b/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DbContextModelCustomizer.cs @@ -0,0 +1,72 @@ +using Microsoft.EntityFrameworkCore.Metadata; + +namespace TestNamespace; + +public partial class DbContextModel +{ + private string DefaultSchema { get; init; } = "custom"; + + partial void Customize() + { + RemoveAnnotation("Relational:DefaultSchema"); + AddAnnotation("Relational:DefaultSchema", DefaultSchema); + RemoveRuntimeAnnotation("Relational:RelationalModel"); + + foreach (RuntimeEntityType entityType in ((IModel)this).GetEntityTypes()) + { + Customize(entityType); + + foreach (var key in entityType.GetDeclaredKeys()) + { + key.RemoveRuntimeAnnotation(RelationalAnnotationNames.UniqueConstraintMappings); + } + + foreach (var index in entityType.GetDeclaredIndexes()) + { + index.RemoveRuntimeAnnotation(RelationalAnnotationNames.TableIndexMappings); + } + + foreach (var foreignKey in entityType.GetDeclaredForeignKeys()) + { + foreignKey.RemoveRuntimeAnnotation(RelationalAnnotationNames.ForeignKeyMappings); + } + + var tableName = entityType.FindAnnotation("Relational:TableName")?.Value as string; + if (string.IsNullOrEmpty(tableName)) + continue; + + entityType.SetAnnotation("Relational:Schema", DefaultSchema); + } + } + + private static void Customize(RuntimeTypeBase entityType) + { + entityType.RemoveRuntimeAnnotation(RelationalAnnotationNames.DefaultMappings); + entityType.RemoveRuntimeAnnotation(RelationalAnnotationNames.TableMappings); + entityType.RemoveRuntimeAnnotation(RelationalAnnotationNames.ViewMappings); + entityType.RemoveRuntimeAnnotation(RelationalAnnotationNames.SqlQueryMappings); + entityType.RemoveRuntimeAnnotation(RelationalAnnotationNames.FunctionMappings); + entityType.RemoveRuntimeAnnotation(RelationalAnnotationNames.InsertStoredProcedureMappings); + entityType.RemoveRuntimeAnnotation(RelationalAnnotationNames.DeleteStoredProcedureMappings); + entityType.RemoveRuntimeAnnotation(RelationalAnnotationNames.UpdateStoredProcedureMappings); + + foreach (var property in entityType.GetDeclaredProperties()) + { + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.DefaultColumnMappings); + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.TableColumnMappings); + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.ViewColumnMappings); + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.SqlQueryColumnMappings); + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.FunctionColumnMappings); + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.InsertStoredProcedureParameterMappings); + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.DeleteStoredProcedureParameterMappings); + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.UpdateStoredProcedureParameterMappings); + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.InsertStoredProcedureResultColumnMappings); + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.UpdateStoredProcedureResultColumnMappings); + } + + foreach (var complexProperty in entityType.GetDeclaredComplexProperties()) + { + Customize(complexProperty.ComplexType); + } + } +} \ No newline at end of file diff --git a/test/EFCore.Sqlite.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DataEntityType.cs b/test/EFCore.Sqlite.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DataEntityType.cs new file mode 100644 index 00000000000..a0cb6fe06e0 --- /dev/null +++ b/test/EFCore.Sqlite.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DataEntityType.cs @@ -0,0 +1,91 @@ +// +using System; +using System.Collections; +using System.Linq; +using System.Reflection; +using Microsoft.EntityFrameworkCore.ChangeTracking; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Scaffolding; +using Microsoft.EntityFrameworkCore.Sqlite.Storage.Internal; +using Microsoft.EntityFrameworkCore.Storage; + +#pragma warning disable 219, 612, 618 +#nullable disable + +namespace TestNamespace +{ + internal partial class DataEntityType + { + public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType baseEntityType = null) + { + var runtimeEntityType = model.AddEntityType( + "Microsoft.EntityFrameworkCore.Scaffolding.CompiledModelTestBase+Data", + typeof(CompiledModelTestBase.Data), + baseEntityType, + propertyCount: 2, + keyCount: 1); + + var id = runtimeEntityType.AddProperty( + "Id", + typeof(int), + valueGenerated: ValueGenerated.OnAdd, + afterSaveBehavior: PropertySaveBehavior.Throw, + sentinel: 0); + id.TypeMapping = IntTypeMapping.Default.Clone( + comparer: new ValueComparer( + (int v1, int v2) => v1 == v2, + (int v) => v, + (int v) => v), + keyComparer: new ValueComparer( + (int v1, int v2) => v1 == v2, + (int v) => v, + (int v) => v), + providerValueComparer: new ValueComparer( + (int v1, int v2) => v1 == v2, + (int v) => v, + (int v) => v), + mappingInfo: new RelationalTypeMappingInfo( + storeTypeName: "INTEGER")); + + var blob = runtimeEntityType.AddProperty( + "Blob", + typeof(byte[]), + propertyInfo: typeof(CompiledModelTestBase.Data).GetProperty("Blob", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly), + fieldInfo: typeof(CompiledModelTestBase.Data).GetField("k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly), + nullable: true); + blob.TypeMapping = SqliteByteArrayTypeMapping.Default.Clone( + comparer: new ValueComparer( + (Byte[] v1, Byte[] v2) => StructuralComparisons.StructuralEqualityComparer.Equals((object)v1, (object)v2), + (Byte[] v) => v.GetHashCode(), + (Byte[] v) => v), + keyComparer: new ValueComparer( + (Byte[] v1, Byte[] v2) => StructuralComparisons.StructuralEqualityComparer.Equals((object)v1, (object)v2), + (Byte[] v) => StructuralComparisons.StructuralEqualityComparer.GetHashCode((object)v), + (Byte[] source) => source.ToArray()), + providerValueComparer: new ValueComparer( + (Byte[] v1, Byte[] v2) => StructuralComparisons.StructuralEqualityComparer.Equals((object)v1, (object)v2), + (Byte[] v) => StructuralComparisons.StructuralEqualityComparer.GetHashCode((object)v), + (Byte[] source) => source.ToArray())); + + var key = runtimeEntityType.AddKey( + new[] { id }); + runtimeEntityType.SetPrimaryKey(key); + + return runtimeEntityType; + } + + public static void CreateAnnotations(RuntimeEntityType runtimeEntityType) + { + runtimeEntityType.AddAnnotation("Relational:FunctionName", null); + runtimeEntityType.AddAnnotation("Relational:Schema", null); + runtimeEntityType.AddAnnotation("Relational:SqlQuery", null); + runtimeEntityType.AddAnnotation("Relational:TableName", "Data"); + runtimeEntityType.AddAnnotation("Relational:ViewName", null); + runtimeEntityType.AddAnnotation("Relational:ViewSchema", null); + + Customize(runtimeEntityType); + } + + static partial void Customize(RuntimeEntityType runtimeEntityType); + } +} diff --git a/test/EFCore.Sqlite.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DbContextModel.cs b/test/EFCore.Sqlite.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DbContextModel.cs new file mode 100644 index 00000000000..583ee4d90cc --- /dev/null +++ b/test/EFCore.Sqlite.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DbContextModel.cs @@ -0,0 +1,48 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; + +#pragma warning disable 219, 612, 618 +#nullable disable + +namespace TestNamespace +{ + [DbContext(typeof(DbContext))] + public partial class DbContextModel : RuntimeModel + { + private static readonly bool _useOldBehavior31751 = + System.AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue31751", out var enabled31751) && enabled31751; + + static DbContextModel() + { + var model = new DbContextModel(); + + if (_useOldBehavior31751) + { + model.Initialize(); + } + else + { + var thread = new System.Threading.Thread(RunInitialization, 10 * 1024 * 1024); + thread.Start(); + thread.Join(); + + void RunInitialization() + { + model.Initialize(); + } + } + + model.Customize(); + _instance = (DbContextModel)model.FinalizeModel(); + } + + private static DbContextModel _instance; + public static IModel Instance => _instance; + + partial void Initialize(); + + partial void Customize(); + } +} diff --git a/test/EFCore.Sqlite.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DbContextModelBuilder.cs b/test/EFCore.Sqlite.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DbContextModelBuilder.cs new file mode 100644 index 00000000000..3a070a508d3 --- /dev/null +++ b/test/EFCore.Sqlite.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DbContextModelBuilder.cs @@ -0,0 +1,80 @@ +// +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Metadata.Internal; + +#pragma warning disable 219, 612, 618 +#nullable disable + +namespace TestNamespace +{ + public partial class DbContextModel + { + private DbContextModel() + : base(skipDetectChanges: false, modelId: new Guid("00000000-0000-0000-0000-000000000000"), entityTypeCount: 1) + { + } + + partial void Initialize() + { + var data = DataEntityType.Create(this); + + DataEntityType.CreateAnnotations(data); + + AddRuntimeAnnotation("Relational:RelationalModel", CreateRelationalModel()); + } + + private IRelationalModel CreateRelationalModel() + { + var relationalModel = new RelationalModel(this); + + var data = FindEntityType("Microsoft.EntityFrameworkCore.Scaffolding.CompiledModelTestBase+Data")!; + + var defaultTableMappings = new List>(); + data.SetRuntimeAnnotation("Relational:DefaultMappings", defaultTableMappings); + var microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDataTableBase = new TableBase("Microsoft.EntityFrameworkCore.Scaffolding.CompiledModelTestBase+Data", null, relationalModel); + var blobColumnBase = new ColumnBase("Blob", "BLOB", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDataTableBase) + { + IsNullable = true + }; + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDataTableBase.Columns.Add("Blob", blobColumnBase); + var idColumnBase = new ColumnBase("Id", "INTEGER", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDataTableBase); + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDataTableBase.Columns.Add("Id", idColumnBase); + relationalModel.DefaultTables.Add("Microsoft.EntityFrameworkCore.Scaffolding.CompiledModelTestBase+Data", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDataTableBase); + var microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDataMappingBase = new TableMappingBase(data, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDataTableBase, null); + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDataTableBase.AddTypeMapping(microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDataMappingBase, false); + defaultTableMappings.Add(microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDataMappingBase); + RelationalModel.CreateColumnMapping((ColumnBase)idColumnBase, data.FindProperty("Id")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDataMappingBase); + RelationalModel.CreateColumnMapping((ColumnBase)blobColumnBase, data.FindProperty("Blob")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBaseDataMappingBase); + + var tableMappings = new List(); + data.SetRuntimeAnnotation("Relational:TableMappings", tableMappings); + var dataTable = new Table("Data", null, relationalModel); + var idColumn = new Column("Id", "INTEGER", dataTable); + dataTable.Columns.Add("Id", idColumn); + var blobColumn = new Column("Blob", "BLOB", dataTable) + { + IsNullable = true + }; + dataTable.Columns.Add("Blob", blobColumn); + var pK_Data = new UniqueConstraint("PK_Data", dataTable, new[] { idColumn }); + dataTable.PrimaryKey = pK_Data; + var pK_DataUc = RelationalModel.GetKey(this, + "Microsoft.EntityFrameworkCore.Scaffolding.CompiledModelTestBase+Data", + new[] { "Id" }); + pK_Data.MappedKeys.Add(pK_DataUc); + RelationalModel.GetOrCreateUniqueConstraints(pK_DataUc).Add(pK_Data); + dataTable.UniqueConstraints.Add("PK_Data", pK_Data); + relationalModel.Tables.Add(("Data", null), dataTable); + var dataTableMapping = new TableMapping(data, dataTable, null); + dataTable.AddTypeMapping(dataTableMapping, false); + tableMappings.Add(dataTableMapping); + RelationalModel.CreateColumnMapping(idColumn, data.FindProperty("Id")!, dataTableMapping); + RelationalModel.CreateColumnMapping(blobColumn, data.FindProperty("Blob")!, dataTableMapping); + return relationalModel.MakeReadOnly(); + } + } +} diff --git a/test/EFCore.Sqlite.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DbContextModelCustomizer.cs b/test/EFCore.Sqlite.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DbContextModelCustomizer.cs new file mode 100644 index 00000000000..8d477de97cb --- /dev/null +++ b/test/EFCore.Sqlite.FunctionalTests/Scaffolding/Baselines/Dynamic_schema/DbContextModelCustomizer.cs @@ -0,0 +1,72 @@ +using Microsoft.EntityFrameworkCore.Metadata; + +namespace TestNamespace; + +public partial class DbContextModel +{ + private string DefaultSchema { get; init; } = "custom"; + + partial void Customize() + { + RemoveAnnotation("Relational:DefaultSchema"); + AddAnnotation("Relational:DefaultSchema", DefaultSchema); + RemoveRuntimeAnnotation("Relational:RelationalModel"); + + foreach (RuntimeEntityType entityType in ((IModel)this).GetEntityTypes()) + { + Customize(entityType); + + foreach (var key in entityType.GetDeclaredKeys()) + { + key.RemoveRuntimeAnnotation(RelationalAnnotationNames.UniqueConstraintMappings); + } + + foreach (var index in entityType.GetDeclaredIndexes()) + { + index.RemoveRuntimeAnnotation(RelationalAnnotationNames.TableIndexMappings); + } + + foreach (var foreignKey in entityType.GetDeclaredForeignKeys()) + { + foreignKey.RemoveRuntimeAnnotation(RelationalAnnotationNames.ForeignKeyMappings); + } + + var tableName = entityType.FindAnnotation("Relational:TableName")?.Value as string; + if (string.IsNullOrEmpty(tableName)) + continue; + + entityType.SetAnnotation("Relational:Schema", DefaultSchema); + } + } + + private static void Customize(RuntimeTypeBase entityType) + { + entityType.RemoveRuntimeAnnotation(RelationalAnnotationNames.DefaultMappings); + entityType.RemoveRuntimeAnnotation(RelationalAnnotationNames.TableMappings); + entityType.RemoveRuntimeAnnotation(RelationalAnnotationNames.ViewMappings); + entityType.RemoveRuntimeAnnotation(RelationalAnnotationNames.SqlQueryMappings); + entityType.RemoveRuntimeAnnotation(RelationalAnnotationNames.FunctionMappings); + entityType.RemoveRuntimeAnnotation(RelationalAnnotationNames.InsertStoredProcedureMappings); + entityType.RemoveRuntimeAnnotation(RelationalAnnotationNames.DeleteStoredProcedureMappings); + entityType.RemoveRuntimeAnnotation(RelationalAnnotationNames.UpdateStoredProcedureMappings); + + foreach (var property in entityType.GetDeclaredProperties()) + { + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.DefaultColumnMappings); + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.TableColumnMappings); + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.ViewColumnMappings); + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.SqlQueryColumnMappings); + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.FunctionColumnMappings); + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.InsertStoredProcedureParameterMappings); + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.DeleteStoredProcedureParameterMappings); + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.UpdateStoredProcedureParameterMappings); + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.InsertStoredProcedureResultColumnMappings); + property.RemoveRuntimeAnnotation(RelationalAnnotationNames.UpdateStoredProcedureResultColumnMappings); + } + + foreach (var complexProperty in entityType.GetDeclaredComplexProperties()) + { + Customize(complexProperty.ComplexType); + } + } +} \ No newline at end of file