From be416d99300f3f01a9880061d8edb0f605d42916 Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Mon, 17 May 2021 12:40:02 -0700 Subject: [PATCH] Add pre-convention model configuration infrastructure Fixes #12229 --- src/EFCore/DbContext.cs | 15 + src/EFCore/Infrastructure/ModelSource.cs | 6 +- .../Metadata/Internal/ClrAccessorFactory.cs | 4 +- src/EFCore/Metadata/Internal/Model.cs | 21 +- .../Metadata/Internal/ModelConfiguration.cs | 33 ++ src/EFCore/ModelBuilder.cs | 21 +- src/EFCore/ModelConfigurationBuilder.cs | 87 +++++ .../CosmosModelValidatorTest.cs | 59 ++- .../CosmosModelBuilderGenericTest.cs | 29 +- .../Design/CSharpMigrationsGeneratorTest.cs | 27 +- .../Migrations/ModelSnapshotSqlServerTest.cs | 162 ++++----- .../Internal/CSharpModelGeneratorTest.cs | 2 +- .../Internal/ModelCodeGeneratorTestBase.cs | 2 +- .../InMemoryDatabaseCreatorTest.cs | 22 -- .../InMemoryValueGeneratorSelectorTest.cs | 2 +- .../InMemoryModelValidatorTest.cs | 2 +- .../InMemoryModelBuilderGenericTest.cs | 24 +- .../MigrationsInfrastructureTestBase.cs | 3 - .../MigrationsSqlGeneratorTestBase.cs | 10 +- ...ionalModelValidatorTest.PropertyMapping.cs | 42 +++ .../RelationalModelValidatorTest.cs | 337 +++++++++++------- .../TableValuedDbFunctionConventionTest.cs | 6 +- .../Metadata/DbFunctionMetadataTests.cs | 43 +-- .../Metadata/RelationalModelTest.cs | 6 +- .../Internal/MigrationsModelDifferTestBase.cs | 25 +- .../Storage/RelationalParameterBuilderTest.cs | 15 +- .../Update/ModificationCommandComparerTest.cs | 8 +- .../Update/ModificationCommandTest.cs | 5 +- .../F1FixtureBase.cs | 2 +- .../OptimisticConcurrencyTestBase.cs | 4 +- .../TestUtilities/TestHelpers.cs | 147 ++++++-- .../ValueConvertersEndToEndTestBase.cs | 60 ++-- .../SqlServerModelValidatorTest.cs | 91 +++-- ...lServerMigrationsAnnotationProviderTest.cs | 4 +- .../SqlServerModelBuilderGenericTest.cs | 29 +- .../SqliteModelValidatorTest.cs | 12 +- .../SqliteMigrationAnnotationProviderTest.cs | 4 +- .../ModelValidatorTest.PropertyMapping.cs | 258 ++++++++++++++ .../Infrastructure/ModelValidatorTest.cs | 325 +++++++++-------- .../Infrastructure/ModelValidatorTestBase.cs | 51 +-- .../Internal/ClrPropertyGetterFactoryTest.cs | 14 +- .../Metadata/MetadataBuilderTest.cs | 4 +- ...delBuilderGenericRelationshipStringTest.cs | 20 +- ...ModelBuilderGenericRelationshipTypeTest.cs | 8 +- .../ModelBuilding/ModelBuilderGenericTest.cs | 40 +-- .../ModelBuilderNonGenericStringTest.cs | 20 +- .../ModelBuilderNonGenericTest.cs | 40 +-- ...lBuilderNonGenericUnqualifiedStringTest.cs | 8 +- .../ModelBuilding/ModelBuilderTestBase.cs | 33 +- .../ModelBuilding/ShadowEntityTypeTest.cs | 6 +- .../ValueGeneratorSelectorTest.cs | 2 +- 51 files changed, 1373 insertions(+), 827 deletions(-) create mode 100644 src/EFCore/Metadata/Internal/ModelConfiguration.cs create mode 100644 src/EFCore/ModelConfigurationBuilder.cs create mode 100644 test/EFCore.Relational.Tests/Infrastructure/RelationalModelValidatorTest.PropertyMapping.cs create mode 100644 test/EFCore.Tests/Infrastructure/ModelValidatorTest.PropertyMapping.cs diff --git a/src/EFCore/DbContext.cs b/src/EFCore/DbContext.cs index 23e6ae18a73..168ca6c6246 100644 --- a/src/EFCore/DbContext.cs +++ b/src/EFCore/DbContext.cs @@ -437,6 +437,21 @@ protected internal virtual void OnConfiguring(DbContextOptionsBuilder optionsBui { } + /// + /// Override this method to set defaults and configure conventions before they run. This method is invoked before + /// . + /// + /// + /// If a model is explicitly set on the options for this context (via ) + /// then this method will not be run. + /// + /// + /// The builder being used to set defaults and configure conventions that will be used to build the model for this context. + /// + protected internal virtual void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) + { + } + /// /// Override this method to further configure the model that was discovered by convention from the entity types /// exposed in properties on your derived context. The resulting model may be cached diff --git a/src/EFCore/Infrastructure/ModelSource.cs b/src/EFCore/Infrastructure/ModelSource.cs index 57a55cc6d2d..7b68b597921 100644 --- a/src/EFCore/Infrastructure/ModelSource.cs +++ b/src/EFCore/Infrastructure/ModelSource.cs @@ -199,7 +199,11 @@ public ModelSource(ModelSourceDependencies dependencies) { Check.DebugAssert(context != null, "context == null"); - var modelBuilder = new ModelBuilder(conventionSetBuilder.CreateConventionSet(), modelDependencies); + var modelConfigurationBuilder = new ModelConfigurationBuilder(conventionSetBuilder.CreateConventionSet()); + + context.ConfigureConventions(modelConfigurationBuilder); + + var modelBuilder = modelConfigurationBuilder.CreateModelBuilder(modelDependencies); Dependencies.ModelCustomizer.Customize(modelBuilder, context); diff --git a/src/EFCore/Metadata/Internal/ClrAccessorFactory.cs b/src/EFCore/Metadata/Internal/ClrAccessorFactory.cs index 139ad59f8ed..413d41ed2a5 100644 --- a/src/EFCore/Metadata/Internal/ClrAccessorFactory.cs +++ b/src/EFCore/Metadata/Internal/ClrAccessorFactory.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using System.Reflection; +using System.Runtime.ExceptionServices; namespace Microsoft.EntityFrameworkCore.Metadata.Internal { @@ -61,7 +62,8 @@ protected virtual TAccessor Create(MemberInfo memberInfo, IPropertyBase? propert } catch (TargetInvocationException e) when (e.InnerException != null) { - throw e.InnerException; + ExceptionDispatchInfo.Capture(e.InnerException).Throw(); + throw; } } diff --git a/src/EFCore/Metadata/Internal/Model.cs b/src/EFCore/Metadata/Internal/Model.cs index 412f3342f5c..d0128457e0c 100644 --- a/src/EFCore/Metadata/Internal/Model.cs +++ b/src/EFCore/Metadata/Internal/Model.cs @@ -36,7 +36,10 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Internal public class Model : ConventionAnnotatable, IMutableModel, IConventionModel, IRuntimeModel { /// - /// The CLR type that is used for property bag entity types when no other type is specified. + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public static readonly Type DefaultPropertyBagType = typeof(Dictionary); @@ -49,11 +52,11 @@ public class Model : ConventionAnnotatable, IMutableModel, IConventionModel, IRu private ConventionDispatcher? _conventionDispatcher; private IList? _modelFinalizedConventions; + private ModelDependencies? _scopedModelDependencies; private bool? _skipDetectChanges; private ChangeTrackingStrategy? _changeTrackingStrategy; private ConfigurationSource? _changeTrackingStrategyConfigurationSource; - private ModelDependencies? _scopedModelDependencies; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -72,7 +75,7 @@ public Model() /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public Model(ConventionSet conventions, ModelDependencies? modelDependencies = null) + public Model(ConventionSet conventions, ModelDependencies? modelDependencies = null, ModelConfiguration? modelConfiguration = null) { if (modelDependencies != null) { @@ -83,6 +86,7 @@ public Model(ConventionSet conventions, ModelDependencies? modelDependencies = n _conventionDispatcher = dispatcher; _modelFinalizedConventions = conventions.ModelFinalizedConventions; Builder = builder; + Configuration = modelConfiguration; dispatcher.OnModelInitialized(builder); } @@ -124,6 +128,14 @@ public virtual ConventionDispatcher ConventionDispatcher /// public virtual InternalModelBuilder Builder { [DebuggerStepThrough] get; } + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public virtual ModelConfiguration? Configuration { get; private set; } + /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -575,7 +587,7 @@ public virtual bool IsShared(Type type) /// public virtual ConfigurationSource? FindIgnoredConfigurationSource(string name) => _ignoredTypeNames.TryGetValue(Check.NotEmpty(name, nameof(name)), out var ignoredConfigurationSource) - ? (ConfigurationSource?)ignoredConfigurationSource + ? ignoredConfigurationSource : null; /// @@ -859,6 +871,7 @@ public virtual IModel FinalizeModel() if (finalizedModel is Model model) { + model.Configuration = null; finalizedModel = model.MakeReadonly(); } diff --git a/src/EFCore/Metadata/Internal/ModelConfiguration.cs b/src/EFCore/Metadata/Internal/ModelConfiguration.cs new file mode 100644 index 00000000000..544acfe0838 --- /dev/null +++ b/src/EFCore/Metadata/Internal/ModelConfiguration.cs @@ -0,0 +1,33 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.EntityFrameworkCore.Metadata.Internal +{ + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public partial class ModelConfiguration + { + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public ModelConfiguration() + { + } + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public virtual bool IsEmpty() + => true; + } +} diff --git a/src/EFCore/ModelBuilder.cs b/src/EFCore/ModelBuilder.cs index 048f7a42dbe..b852ff13a5c 100644 --- a/src/EFCore/ModelBuilder.cs +++ b/src/EFCore/ModelBuilder.cs @@ -35,7 +35,7 @@ public class ModelBuilder : IInfrastructure /// /// The conventions to be applied to the model. public ModelBuilder(ConventionSet conventions) - : this(conventions, null, true) + : this(conventions, null, null) { } @@ -46,16 +46,23 @@ public ModelBuilder(ConventionSet conventions) /// The conventions to be applied to the model. /// The dependencies object for the model. public ModelBuilder(ConventionSet conventions, ModelDependencies modelDependencies) - : this(conventions, modelDependencies, true) + : this(conventions, modelDependencies, null) { Check.NotNull(modelDependencies, nameof(modelDependencies)); } - private ModelBuilder(ConventionSet conventions, ModelDependencies? modelDependencies, bool _) + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + [EntityFrameworkInternal] + public ModelBuilder(ConventionSet conventions, ModelDependencies? modelDependencies, ModelConfiguration? modelConfiguration) { Check.NotNull(conventions, nameof(conventions)); - _builder = new Model(conventions, modelDependencies).Builder; + _builder = new Model(conventions, modelDependencies, modelConfiguration).Builder; _builder.Metadata.SetProductVersion(ProductInfo.GetVersion()); } @@ -65,7 +72,7 @@ private ModelBuilder(ConventionSet conventions, ModelDependencies? modelDependen /// Initializes a new instance of the class with no conventions. /// /// - /// Warning: conventions are typically needed to build a correct model. + /// Warning: conventions are needed to build a correct model. /// /// public ModelBuilder() @@ -262,7 +269,6 @@ public virtual ModelBuilder Entity(Action> b Action> buildAction) where TEntity : class { - Check.NotEmpty(name, nameof(name)); Check.NotNull(buildAction, nameof(buildAction)); buildAction(SharedTypeEntity(name)); @@ -288,7 +294,6 @@ public virtual ModelBuilder Entity(Action> b /// public virtual ModelBuilder Entity(Type type, Action buildAction) { - Check.NotNull(type, nameof(type)); Check.NotNull(buildAction, nameof(buildAction)); buildAction(Entity(type)); @@ -315,7 +320,6 @@ public virtual ModelBuilder Entity(Type type, Action buildAct /// public virtual ModelBuilder Entity(string name, Action buildAction) { - Check.NotEmpty(name, nameof(name)); Check.NotNull(buildAction, nameof(buildAction)); buildAction(Entity(name)); @@ -352,7 +356,6 @@ public virtual ModelBuilder Entity(string name, Action buildA Type type, Action buildAction) { - Check.NotEmpty(name, nameof(name)); Check.NotNull(type, nameof(type)); Check.NotNull(buildAction, nameof(buildAction)); diff --git a/src/EFCore/ModelConfigurationBuilder.cs b/src/EFCore/ModelConfigurationBuilder.cs new file mode 100644 index 00000000000..56f52bb45b9 --- /dev/null +++ b/src/EFCore/ModelConfigurationBuilder.cs @@ -0,0 +1,87 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.ComponentModel; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata.Conventions; +using Microsoft.EntityFrameworkCore.Metadata.Internal; +using Microsoft.EntityFrameworkCore.Utilities; + +namespace Microsoft.EntityFrameworkCore +{ + /// + /// + /// Provides a simple API surface for setting defaults and configuring conventions before they run. + /// + /// + /// You can use to configure the conventions for a context by overriding + /// on your derived context. + /// Alternatively you can create the model externally and set it on a instance + /// that is passed to the context constructor. + /// + /// + public class ModelConfigurationBuilder + { + private readonly ModelConfiguration _modelConfiguration = new(); + private readonly ConventionSet _conventions; + + /// + /// Initializes a new instance of the . + /// + /// The conventions to be applied during model building. + public ModelConfigurationBuilder(ConventionSet conventions) + { + Check.NotNull(conventions, nameof(conventions)); + + _conventions = conventions; + } + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + [EntityFrameworkInternal] + protected virtual ModelConfiguration ModelConfiguration => _modelConfiguration; + + /// + /// Creates the configured used to create the model. This is done automatically when using + /// ; this method allows it to be run + /// explicitly in cases where the automatic execution is not possible. + /// + /// The dependencies object used during model building. + /// The configured . + public virtual ModelBuilder CreateModelBuilder(ModelDependencies? modelDependencies) + => new(_conventions, modelDependencies, _modelConfiguration.IsEmpty() ? null : _modelConfiguration); + + #region Hidden System.Object members + + /// + /// Returns a string that represents the current object. + /// + /// A string that represents the current object. + [EditorBrowsable(EditorBrowsableState.Never)] + public override string? ToString() + => base.ToString(); + + /// + /// Determines whether the specified object is equal to the current object. + /// + /// The object to compare with the current object. + /// if the specified object is equal to the current object; otherwise, . + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object? obj) + => base.Equals(obj); + + /// + /// Serves as the default hash function. + /// + /// A hash code for the current object. + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() + => base.GetHashCode(); + + #endregion + } +} diff --git a/test/EFCore.Cosmos.Tests/Infrastructure/CosmosModelValidatorTest.cs b/test/EFCore.Cosmos.Tests/Infrastructure/CosmosModelValidatorTest.cs index 0e47d0e3ea3..790d7a7868d 100644 --- a/test/EFCore.Cosmos.Tests/Infrastructure/CosmosModelValidatorTest.cs +++ b/test/EFCore.Cosmos.Tests/Infrastructure/CosmosModelValidatorTest.cs @@ -15,8 +15,7 @@ public virtual void Passes_on_valid_model() var modelBuilder = CreateConventionalModelBuilder(); modelBuilder.Entity(); - var model = modelBuilder.Model; - Validate(model); + Validate(modelBuilder); } [ConditionalFact] @@ -25,7 +24,7 @@ public virtual void Passes_on_valid_keyless_entity_type() var modelBuilder = CreateConventionalModelBuilder(); modelBuilder.Entity().HasPartitionKey(c => c.PartitionId).HasNoKey(); - var model = Validate(modelBuilder.Model); + var model = Validate(modelBuilder); Assert.Empty(model.FindEntityType(typeof(Customer)).GetKeys()); } @@ -45,8 +44,7 @@ public virtual void Detects_missing_id_property() b.Ignore(o => o.Products); }); - var model = modelBuilder.Model; - VerifyError(CosmosStrings.NoIdProperty(typeof(Order).Name), model); + VerifyError(CosmosStrings.NoIdProperty(typeof(Order).Name), modelBuilder); } [ConditionalFact] @@ -65,8 +63,7 @@ public virtual void Detects_non_key_id_property() b.Ignore(o => o.Products); }); - var model = modelBuilder.Model; - VerifyError(CosmosStrings.NoIdKey(typeof(Order).Name, "id"), model); + VerifyError(CosmosStrings.NoIdKey(typeof(Order).Name, "id"), modelBuilder); } [ConditionalFact] @@ -86,8 +83,7 @@ public virtual void Detects_non_string_id_property() b.Ignore(o => o.Products); }); - var model = modelBuilder.Model; - VerifyError(CosmosStrings.IdNonStringStoreType("id", typeof(Order).Name, "int"), model); + VerifyError(CosmosStrings.IdNonStringStoreType("id", typeof(Order).Name, "int"), modelBuilder); } [ConditionalFact] @@ -98,7 +94,7 @@ public virtual void Passes_on_valid_partition_keys() modelBuilder.Entity().ToContainer("Orders").HasPartitionKey(o => o.PartitionId) .Property(o => o.PartitionId).HasConversion(); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalFact] @@ -114,7 +110,7 @@ public virtual void Passes_PK_partition_key() b.Ignore(o => o.Products); }); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalFact] @@ -134,7 +130,7 @@ public virtual void Detects_non_key_partition_key_property() b.Ignore(o => o.Products); }); - VerifyError(CosmosStrings.NoPartitionKeyKey(typeof(Order).Name, nameof(Order.PartitionId), "id"), modelBuilder.Model); + VerifyError(CosmosStrings.NoPartitionKeyKey(typeof(Order).Name, nameof(Order.PartitionId), "id"), modelBuilder); } [ConditionalFact] @@ -143,8 +139,7 @@ public virtual void Detects_missing_partition_key_property() var modelBuilder = CreateConventionalModelBuilder(); modelBuilder.Entity().HasPartitionKey("PartitionKey"); - var model = modelBuilder.Model; - VerifyError(CosmosStrings.PartitionKeyMissingProperty(typeof(Order).Name, "PartitionKey"), model); + VerifyError(CosmosStrings.PartitionKeyMissingProperty(typeof(Order).Name, "PartitionKey"), modelBuilder); } [ConditionalFact] @@ -154,8 +149,7 @@ public virtual void Detects_missing_partition_key_on_first_type() modelBuilder.Entity().ToContainer("Orders"); modelBuilder.Entity().ToContainer("Orders").HasPartitionKey(c => c.PartitionId); - var model = modelBuilder.Model; - VerifyError(CosmosStrings.NoPartitionKey(typeof(Customer).Name, "Orders"), model); + VerifyError(CosmosStrings.NoPartitionKey(typeof(Customer).Name, "Orders"), modelBuilder); } [ConditionalFact] @@ -165,8 +159,7 @@ public virtual void Detects_missing_partition_keys_one_last_type() modelBuilder.Entity().ToContainer("Orders").HasPartitionKey(c => c.PartitionId); modelBuilder.Entity().ToContainer("Orders"); - var model = modelBuilder.Model; - VerifyError(CosmosStrings.NoPartitionKey(typeof(Order).Name, "Orders"), model); + VerifyError(CosmosStrings.NoPartitionKey(typeof(Order).Name, "Orders"), modelBuilder); } [ConditionalFact] @@ -177,11 +170,10 @@ public virtual void Detects_partition_keys_mapped_to_different_properties() .Property(c => c.PartitionId).ToJsonProperty("pk"); modelBuilder.Entity().ToContainer("Orders").HasPartitionKey(c => c.PartitionId); - var model = modelBuilder.Model; VerifyError( CosmosStrings.PartitionKeyStoreNameMismatch( nameof(Customer.PartitionId), typeof(Customer).Name, "pk", nameof(Order.PartitionId), typeof(Order).Name, - nameof(Order.PartitionId)), model); + nameof(Order.PartitionId)), modelBuilder); } [ConditionalFact] @@ -192,10 +184,9 @@ public virtual void Detects_partition_key_of_different_type() modelBuilder.Entity().ToContainer("Orders").HasPartitionKey(o => o.PartitionId) .Property(c => c.PartitionId).HasConversion(); - var model = modelBuilder.Model; VerifyError( CosmosStrings.PartitionKeyNonStringStoreType( - nameof(Customer.PartitionId), typeof(Order).Name, "int"), model); + nameof(Customer.PartitionId), typeof(Order).Name, "int"), modelBuilder); } [ConditionalFact] @@ -209,10 +200,9 @@ public virtual void Detects_properties_mapped_to_same_property() ob.Property(o => o.PartitionId).ToJsonProperty("Details"); }); - var model = modelBuilder.Model; VerifyError( CosmosStrings.JsonPropertyCollision( - nameof(Order.PartitionId), nameof(Order.Id), typeof(Order).Name, "Details"), model); + nameof(Order.PartitionId), nameof(Order.Id), typeof(Order).Name, "Details"), modelBuilder); } [ConditionalFact] @@ -226,10 +216,9 @@ public virtual void Detects_property_and_embedded_type_mapped_to_same_property() ob.OwnsOne(o => o.OrderDetails).ToJsonProperty("Details"); }); - var model = modelBuilder.Model; VerifyError( CosmosStrings.JsonPropertyCollision( - nameof(Order.OrderDetails), nameof(Order.PartitionId), typeof(Order).Name, "Details"), model); + nameof(Order.OrderDetails), nameof(Order.PartitionId), typeof(Order).Name, "Details"), modelBuilder); } [ConditionalFact] @@ -239,8 +228,7 @@ public virtual void Detects_missing_discriminator() modelBuilder.Entity().ToContainer("Orders").HasNoDiscriminator(); modelBuilder.Entity().ToContainer("Orders"); - var model = modelBuilder.Model; - VerifyError(CosmosStrings.NoDiscriminatorProperty(typeof(Customer).Name, "Orders"), model); + VerifyError(CosmosStrings.NoDiscriminatorProperty(typeof(Customer).Name, "Orders"), modelBuilder); } [ConditionalFact] @@ -250,8 +238,7 @@ public virtual void Detects_missing_discriminator_value() modelBuilder.Entity().ToContainer("Orders").HasDiscriminator().HasValue(null); modelBuilder.Entity().ToContainer("Orders"); - var model = modelBuilder.Model; - VerifyError(CosmosStrings.NoDiscriminatorValue(typeof(Customer).Name, "Orders"), model); + VerifyError(CosmosStrings.NoDiscriminatorValue(typeof(Customer).Name, "Orders"), modelBuilder); } [ConditionalFact] @@ -261,8 +248,7 @@ public virtual void Detects_duplicate_discriminator_values() modelBuilder.Entity().ToContainer("Orders").HasDiscriminator().HasValue("type"); modelBuilder.Entity().ToContainer("Orders").HasDiscriminator().HasValue("type"); - var model = modelBuilder.Model; - VerifyError(CosmosStrings.DuplicateDiscriminatorValue(typeof(Order).Name, "type", typeof(Customer).Name, "Orders"), model); + VerifyError(CosmosStrings.DuplicateDiscriminatorValue(typeof(Order).Name, "type", typeof(Customer).Name, "Orders"), modelBuilder); } [ConditionalFact] @@ -274,8 +260,7 @@ public virtual void Passes_on_valid_concurrency_token() .Property("_etag") .IsConcurrencyToken(); - var model = modelBuilder.Model; - Validate(model); + Validate(modelBuilder); } [ConditionalFact] @@ -287,8 +272,7 @@ public virtual void Detects_invalid_concurrency_token() .Property("_not_etag") .IsConcurrencyToken(); - var model = modelBuilder.Model; - VerifyError(CosmosStrings.NonETagConcurrencyToken(typeof(Customer).Name, "_not_etag"), model); + VerifyError(CosmosStrings.NonETagConcurrencyToken(typeof(Customer).Name, "_not_etag"), modelBuilder); } [ConditionalFact] @@ -300,8 +284,7 @@ public virtual void Detects_nonString_concurrency_token() .Property("_etag") .IsConcurrencyToken(); - var model = modelBuilder.Model; - VerifyError(CosmosStrings.ETagNonStringStoreType("_etag", typeof(Customer).Name, "int"), model); + VerifyError(CosmosStrings.ETagNonStringStoreType("_etag", typeof(Customer).Name, "int"), modelBuilder); } protected override TestHelpers TestHelpers diff --git a/test/EFCore.Cosmos.Tests/ModelBuilding/CosmosModelBuilderGenericTest.cs b/test/EFCore.Cosmos.Tests/ModelBuilding/CosmosModelBuilderGenericTest.cs index 9e959069d61..99d3b08bfbd 100644 --- a/test/EFCore.Cosmos.Tests/ModelBuilding/CosmosModelBuilderGenericTest.cs +++ b/test/EFCore.Cosmos.Tests/ModelBuilding/CosmosModelBuilderGenericTest.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Collections.Generic; using System.Linq; using Microsoft.EntityFrameworkCore.Metadata.Conventions; @@ -199,8 +200,8 @@ public virtual void No_alternate_key_is_created_if_id_is_partition_key() Assert.Empty(entity.GetKeys().Where(k => k != entity.FindPrimaryKey())); } - protected override TestModelBuilder CreateModelBuilder() - => CreateTestModelBuilder(CosmosTestHelpers.Instance); + protected override TestModelBuilder CreateModelBuilder(Action configure = null) + => CreateTestModelBuilder(CosmosTestHelpers.Instance, configure); } public class CosmosGenericInheritance : GenericInheritance @@ -210,26 +211,26 @@ public override void Can_set_and_remove_base_type() // Fails due to presence of __jObject } - protected override TestModelBuilder CreateModelBuilder() - => CreateTestModelBuilder(CosmosTestHelpers.Instance); + protected override TestModelBuilder CreateModelBuilder(Action configure = null) + => CreateTestModelBuilder(CosmosTestHelpers.Instance, configure); } public class CosmosGenericOneToMany : GenericOneToMany { - protected override TestModelBuilder CreateModelBuilder() - => CreateTestModelBuilder(CosmosTestHelpers.Instance); + protected override TestModelBuilder CreateModelBuilder(Action configure = null) + => CreateTestModelBuilder(CosmosTestHelpers.Instance, configure); } public class CosmosGenericManyToOne : GenericManyToOne { - protected override TestModelBuilder CreateModelBuilder() - => CreateTestModelBuilder(CosmosTestHelpers.Instance); + protected override TestModelBuilder CreateModelBuilder(Action configure = null) + => CreateTestModelBuilder(CosmosTestHelpers.Instance, configure); } public class CosmosGenericOneToOne : GenericOneToOne { - protected override TestModelBuilder CreateModelBuilder() - => CreateTestModelBuilder(CosmosTestHelpers.Instance); + protected override TestModelBuilder CreateModelBuilder(Action configure = null) + => CreateTestModelBuilder(CosmosTestHelpers.Instance, configure); } public class CosmosGenericManyToMany : GenericManyToMany @@ -277,14 +278,14 @@ public virtual void Can_use_shared_type_as_join_entity_with_partition_keys() Assert.Equal("PartitionId", joinType.FindPrimaryKey().Properties.Last().Name); } - protected override TestModelBuilder CreateModelBuilder() - => CreateTestModelBuilder(CosmosTestHelpers.Instance); + protected override TestModelBuilder CreateModelBuilder(Action configure = null) + => CreateTestModelBuilder(CosmosTestHelpers.Instance, configure); } public class CosmosGenericOwnedTypes : GenericOwnedTypes { - protected override TestModelBuilder CreateModelBuilder() - => CreateTestModelBuilder(CosmosTestHelpers.Instance); + protected override TestModelBuilder CreateModelBuilder(Action configure = null) + => CreateTestModelBuilder(CosmosTestHelpers.Instance, configure); } } } diff --git a/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.cs b/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.cs index 6844ffb47a0..a6cd6c30b83 100644 --- a/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.cs +++ b/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.cs @@ -193,7 +193,7 @@ public void Test_new_annotations_handled_for_properties() }; var columnMapping = - $@"{_nl}.{nameof(RelationalPropertyBuilderExtensions.HasColumnType)}(""int"")"; + $@"{_nl}.{nameof(RelationalPropertyBuilderExtensions.HasColumnType)}(""default_int_mapping"")"; // Add a line here if the code generator is supposed to handle this annotation // Note that other tests should be added to check code is generated correctly @@ -204,11 +204,11 @@ public void Test_new_annotations_handled_for_properties() { CoreAnnotationNames.Unicode, (false, $@"{_nl}.{nameof(PropertyBuilder.IsUnicode)}(false){columnMapping}") }, { CoreAnnotationNames.ValueConverter, (new ValueConverter(v => v, v => (int)v), - $@"{_nl}.{nameof(RelationalPropertyBuilderExtensions.HasColumnType)}(""bigint"")") + $@"{_nl}.{nameof(RelationalPropertyBuilderExtensions.HasColumnType)}(""default_long_mapping"")") }, { CoreAnnotationNames.ProviderClrType, - (typeof(long), $@"{_nl}.{nameof(RelationalPropertyBuilderExtensions.HasColumnType)}(""bigint"")") + (typeof(long), $@"{_nl}.{nameof(RelationalPropertyBuilderExtensions.HasColumnType)}(""default_long_mapping"")") }, { RelationalAnnotationNames.ColumnName, @@ -295,7 +295,7 @@ public void Test_new_annotations_handled_for_properties() ? validAnnotations[annotationName].Value : null); - SqlServerTestHelpers.Instance.Finalize(modelBuilder, designTime: true); + modelBuilder.FinalizeModel(designTime: true); var sb = new IndentedStringBuilder(); @@ -390,7 +390,7 @@ public void Snapshot_with_enum_discriminator_uses_converted_values() eb.Property("EnumDiscriminator").HasConversion(); }); - var finalizedModel = SqlServerTestHelpers.Instance.Finalize(modelBuilder, designTime: true); + var finalizedModel = modelBuilder.FinalizeModel(designTime: true); var modelSnapshotCode = generator.GenerateSnapshot( "MyNamespace", @@ -508,7 +508,7 @@ protected override void Down(MigrationBuilder migrationBuilder) migrationCode, ignoreLineEndingDifferences: true); - var modelBuilder = new ModelBuilder(); + var modelBuilder = SqlServerTestHelpers.Instance.CreateConventionBuilder(configure: c => c.RemoveAllConventions()); modelBuilder.HasAnnotation("Some:EnumValue", RegexOptions.Multiline); modelBuilder.HasAnnotation(RelationalAnnotationNames.DbFunctions, new SortedDictionary()); modelBuilder.Entity( @@ -519,8 +519,9 @@ protected override void Down(MigrationBuilder migrationBuilder) eb.Property("C3"); eb.HasKey("Id"); }); + modelBuilder.HasAnnotation(CoreAnnotationNames.ProductVersion, null); - var finalizedModel = SqlServerTestHelpers.Instance.Finalize(modelBuilder, designTime: true); + var finalizedModel = modelBuilder.FinalizeModel(designTime: true); var migrationMetadataCode = generator.GenerateMetadata( "MyNamespace", @@ -652,7 +653,7 @@ public void Snapshots_compile() entityType.SetPrimaryKey(property2); - var finalizedModel = SqlServerTestHelpers.Instance.Finalize(modelBuilder, designTime: true); + var finalizedModel = modelBuilder.FinalizeModel(designTime: true); var modelSnapshotCode = generator.GenerateSnapshot( "MyNamespace", @@ -682,10 +683,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity(""Cheese"", b => { b.Property(""Ham"") - .HasColumnType(""nvarchar(10)""); + .HasColumnType(""just_string(10)""); b.Property(""Pickle"") - .HasColumnType(""nvarchar(10)""); + .HasColumnType(""just_string(10)""); b.HasKey(""Ham""); @@ -696,10 +697,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property(""Id"") .ValueGeneratedOnAdd() - .HasColumnType(""int""); + .HasColumnType(""default_int_mapping""); b.Property(""PropertyWithValueGenerator"") - .HasColumnType(""uniqueidentifier""); + .HasColumnType(""default_guid_mapping""); b.HasKey(""Id""); @@ -768,7 +769,7 @@ public void Snapshot_with_default_values_are_round_tripped() eb.HasKey(e => e.Boolean); }); - var finalizedModel = SqlServerTestHelpers.Instance.Finalize(modelBuilder, designTime: true); + var finalizedModel = modelBuilder.FinalizeModel(designTime: true); var modelSnapshotCode = generator.GenerateSnapshot( "MyNamespace", diff --git a/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs b/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs index 50473f81a2a..f7a73609acf 100644 --- a/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs +++ b/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs @@ -3254,31 +3254,25 @@ public virtual void Property_multiple_annotations_are_stored_in_snapshot() [ConditionalFact] public virtual void Property_without_column_type() { - var modelBuilder = new ModelBuilder(); - var model = modelBuilder.Model; - - modelBuilder - .HasAnnotation(SqlServerAnnotationNames.ValueGenerationStrategy, SqlServerValueGenerationStrategy.IdentityColumn); - - modelBuilder.Entity( - "Building", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() + Test( + builder => { + builder .HasAnnotation(SqlServerAnnotationNames.ValueGenerationStrategy, SqlServerValueGenerationStrategy.IdentityColumn); - b.HasKey("Id"); + builder.Entity( + "Building", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation(SqlServerAnnotationNames.ValueGenerationStrategy, SqlServerValueGenerationStrategy.IdentityColumn); - b.ToTable("Buildings"); - }); + b.HasKey("Id"); - Test( - model.FinalizeModel(), + b.ToTable("Buildings"); + }); + }, AddBoilerPlate( - @" - modelBuilder - .HasAnnotation(""SqlServer:ValueGenerationStrategy"", SqlServerValueGenerationStrategy.IdentityColumn); - + GetHeading() + @" modelBuilder.Entity(""Building"", b => { b.Property(""Id"") @@ -3300,27 +3294,24 @@ public virtual void Property_without_column_type() [ConditionalFact] public virtual void Property_with_identity_column() { - var modelBuilder = new ModelBuilder(); - var model = modelBuilder.Model; - - modelBuilder.Entity( - "Building", b => - { - b.Property("Id").UseIdentityColumn(); - - b.HasKey("Id"); + Test( + builder => { + builder.Entity( + "Building", b => + { + b.Property("Id").UseIdentityColumn(); - b.ToTable("Buildings"); - }); + b.HasKey("Id"); - Test( - model.FinalizeModel(), + b.ToTable("Buildings"); + }); + }, AddBoilerPlate( - @" - + GetHeading() + @" modelBuilder.Entity(""Building"", b => { b.Property(""Id"") + .ValueGeneratedOnAdd() .HasColumnType(""int"") .HasAnnotation(""SqlServer:IdentityIncrement"", 1) .HasAnnotation(""SqlServer:IdentitySeed"", 1) @@ -3342,27 +3333,25 @@ public virtual void Property_with_identity_column() [ConditionalFact] public virtual void Property_with_identity_column_custom_seed() { - var modelBuilder = new ModelBuilder(); - var model = modelBuilder.Model; - - modelBuilder.Entity( - "Building", b => - { - b.Property("Id").UseIdentityColumn(5); + Test( - b.HasKey("Id"); + builder => { + builder.Entity( + "Building", b => + { + b.Property("Id").UseIdentityColumn(seed: 5); - b.ToTable("Buildings"); - }); + b.HasKey("Id"); - Test( - model.FinalizeModel(), + b.ToTable("Buildings"); + }); + }, AddBoilerPlate( - @" - + GetHeading() + @" modelBuilder.Entity(""Building"", b => { b.Property(""Id"") + .ValueGeneratedOnAdd() .HasColumnType(""int"") .HasAnnotation(""SqlServer:IdentityIncrement"", 1) .HasAnnotation(""SqlServer:IdentitySeed"", 5) @@ -3384,27 +3373,25 @@ public virtual void Property_with_identity_column_custom_seed() [ConditionalFact] public virtual void Property_with_identity_column_custom_increment() { - var modelBuilder = new ModelBuilder(); - var model = modelBuilder.Model; - modelBuilder.Entity( - "Building", b => - { - b.Property("Id").UseIdentityColumn(increment: 5); - - b.HasKey("Id"); + Test( + builder => { + builder.Entity( + "Building", b => + { + b.Property("Id").UseIdentityColumn(increment: 5); - b.ToTable("Buildings"); - }); + b.HasKey("Id"); - Test( - model.FinalizeModel(), + b.ToTable("Buildings"); + }); + }, AddBoilerPlate( - @" - + GetHeading() + @" modelBuilder.Entity(""Building"", b => { b.Property(""Id"") + .ValueGeneratedOnAdd() .HasColumnType(""int"") .HasAnnotation(""SqlServer:IdentityIncrement"", 5) .HasAnnotation(""SqlServer:IdentitySeed"", 1) @@ -3426,27 +3413,24 @@ public virtual void Property_with_identity_column_custom_increment() [ConditionalFact] public virtual void Property_with_identity_column_custom_seed_increment() { - var modelBuilder = new ModelBuilder(); - var model = modelBuilder.Model; - - modelBuilder.Entity( - "Building", b => - { - b.Property("Id").UseIdentityColumn(5, 5); + Test( + builder => { + builder.Entity( + "Building", b => + { + b.Property("Id").UseIdentityColumn(5, 5); - b.HasKey("Id"); + b.HasKey("Id"); - b.ToTable("Buildings"); - }); - - Test( - model.FinalizeModel(), + b.ToTable("Buildings"); + }); + }, AddBoilerPlate( - @" - + GetHeading() + @" modelBuilder.Entity(""Building"", b => { b.Property(""Id"") + .ValueGeneratedOnAdd() .HasColumnType(""int"") .HasAnnotation(""SqlServer:IdentityIncrement"", 5) .HasAnnotation(""SqlServer:IdentitySeed"", 5) @@ -5372,22 +5356,13 @@ protected void Test(Action buildModel, string expectedCode, Action modelBuilder.Model.RemoveAnnotation(CoreAnnotationNames.ProductVersion); buildModel(modelBuilder); - var model = modelBuilder.FinalizeModel(); + var model = modelBuilder.FinalizeModel(designTime: true, skipValidation: true); Test(model, expectedCode, assert); } - protected void Test(IModel model, string expectedCode, Action assert) - => Test(model, expectedCode, (m, _) => assert(m)); - protected void Test(IModel model, string expectedCode, Action assert) { - var serviceProvider = SqlServerTestHelpers.Instance.CreateContextServices( - new ServiceCollection() - .AddEntityFrameworkSqlServerNetTopologySuite()); - - serviceProvider.GetService().Initialize(model, designTime: true, validationLogger: null); - var generator = CreateMigrationsGenerator(); var code = generator.GenerateSnapshot("RootNamespace", typeof(DbContext), "Snapshot", model); Assert.Equal(expectedCode, code, ignoreLineEndingDifferences: true); @@ -5428,17 +5403,10 @@ protected IModel BuildModelFromSnapshotSource(string code) return processor.Process(builder.Model); } - protected ModelBuilder CreateConventionalModelBuilder() - { - var serviceProvider = SqlServerTestHelpers.Instance.CreateContextServices( - new ServiceCollection() + protected TestHelpers.TestModelBuilder CreateConventionalModelBuilder() + => SqlServerTestHelpers.Instance.CreateConventionBuilder(customServices: new ServiceCollection() .AddEntityFrameworkSqlServerNetTopologySuite()); - return new ModelBuilder( - serviceProvider.GetService().CreateConventionSet(), - serviceProvider.GetService()); - } - protected CSharpMigrationsGenerator CreateMigrationsGenerator() { var sqlServerTypeMappingSource = new SqlServerTypeMappingSource( diff --git a/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpModelGeneratorTest.cs b/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpModelGeneratorTest.cs index ede61af38ad..7ef2b4ed065 100644 --- a/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpModelGeneratorTest.cs +++ b/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpModelGeneratorTest.cs @@ -32,7 +32,7 @@ public void WriteCode_works() modelBuilder.Entity("TestEntity").Property("Id").HasAnnotation(ScaffoldingAnnotationNames.ColumnOrdinal, 0); var result = generator.GenerateModel( - modelBuilder.FinalizeModel(), + modelBuilder.FinalizeModel(designTime: true), new ModelCodeGenerationOptions { ModelNamespace = "TestNamespace", diff --git a/test/EFCore.Design.Tests/Scaffolding/Internal/ModelCodeGeneratorTestBase.cs b/test/EFCore.Design.Tests/Scaffolding/Internal/ModelCodeGeneratorTestBase.cs index 0c4e62bc580..fac3e76b3b6 100644 --- a/test/EFCore.Design.Tests/Scaffolding/Internal/ModelCodeGeneratorTestBase.cs +++ b/test/EFCore.Design.Tests/Scaffolding/Internal/ModelCodeGeneratorTestBase.cs @@ -25,7 +25,7 @@ public abstract class ModelCodeGeneratorTestBase modelBuilder.Model.RemoveAnnotation(CoreAnnotationNames.ProductVersion); buildModel(modelBuilder); - var model = SqlServerTestHelpers.Instance.Finalize(modelBuilder, designTime: true, skipValidation: true); + var model = modelBuilder.FinalizeModel(designTime: true, skipValidation: true); var generator = CreateServices() .BuildServiceProvider() diff --git a/test/EFCore.InMemory.Tests/InMemoryDatabaseCreatorTest.cs b/test/EFCore.InMemory.Tests/InMemoryDatabaseCreatorTest.cs index bd905a2a743..d2b5894b219 100644 --- a/test/EFCore.InMemory.Tests/InMemoryDatabaseCreatorTest.cs +++ b/test/EFCore.InMemory.Tests/InMemoryDatabaseCreatorTest.cs @@ -126,27 +126,5 @@ private class Fraggle public int Id { get; set; } public string Name { get; set; } } - - private static IModel CreateModel() - { - var modelBuilder = new ModelBuilder(); - - modelBuilder.Entity( - b => - { - b.HasKey(c => c.Id); - b.Property(c => c.Name); - - b.HasData(new Test { Id = 1 }); - }); - - return modelBuilder.FinalizeModel(); - } - - private class Test - { - public int Id { get; set; } - public string Name { get; set; } - } } } diff --git a/test/EFCore.InMemory.Tests/InMemoryValueGeneratorSelectorTest.cs b/test/EFCore.InMemory.Tests/InMemoryValueGeneratorSelectorTest.cs index 32535b054b6..088c21af1f7 100644 --- a/test/EFCore.InMemory.Tests/InMemoryValueGeneratorSelectorTest.cs +++ b/test/EFCore.InMemory.Tests/InMemoryValueGeneratorSelectorTest.cs @@ -105,7 +105,7 @@ private static IModel BuildModel(bool generateValues = true) property.ValueGenerated = generateValues ? ValueGenerated.OnAdd : ValueGenerated.Never; } - return InMemoryTestHelpers.Instance.Finalize(builder); + return builder.FinalizeModel(); } private class AnEntity diff --git a/test/EFCore.InMemory.Tests/Infrastructure/InMemoryModelValidatorTest.cs b/test/EFCore.InMemory.Tests/Infrastructure/InMemoryModelValidatorTest.cs index 8bf9034ccc5..94077218007 100644 --- a/test/EFCore.InMemory.Tests/Infrastructure/InMemoryModelValidatorTest.cs +++ b/test/EFCore.InMemory.Tests/Infrastructure/InMemoryModelValidatorTest.cs @@ -19,7 +19,7 @@ public virtual void Detects_ToQuery_on_derived_keyless_types() VerifyError( CoreStrings.DerivedTypeDefiningQuery("Generic", nameof(Abstract)), - modelBuilder.Model); + modelBuilder); } protected override TestHelpers TestHelpers diff --git a/test/EFCore.InMemory.Tests/ModelBuilding/InMemoryModelBuilderGenericTest.cs b/test/EFCore.InMemory.Tests/ModelBuilding/InMemoryModelBuilderGenericTest.cs index cb3276ef427..12a14654ddc 100644 --- a/test/EFCore.InMemory.Tests/ModelBuilding/InMemoryModelBuilderGenericTest.cs +++ b/test/EFCore.InMemory.Tests/ModelBuilding/InMemoryModelBuilderGenericTest.cs @@ -16,14 +16,14 @@ public class InMemoryModelBuilderGenericTest : ModelBuilderGenericTest { public class InMemoryGenericNonRelationship : GenericNonRelationship { - protected override TestModelBuilder CreateModelBuilder() - => CreateTestModelBuilder(InMemoryTestHelpers.Instance); + protected override TestModelBuilder CreateModelBuilder(Action configure = null) + => CreateTestModelBuilder(InMemoryTestHelpers.Instance, configure); } public class InMemoryGenericInheritance : GenericInheritance { - protected override TestModelBuilder CreateModelBuilder() - => CreateTestModelBuilder(InMemoryTestHelpers.Instance); + protected override TestModelBuilder CreateModelBuilder(Action configure = null) + => CreateTestModelBuilder(InMemoryTestHelpers.Instance, configure); } public class InMemoryGenericOneToMany : GenericOneToMany @@ -140,14 +140,14 @@ private class ModifierGroupHeader public virtual ModifierGroupHeader ModifierGroupHeader2 { get; set; } } - protected override TestModelBuilder CreateModelBuilder() - => CreateTestModelBuilder(InMemoryTestHelpers.Instance); + protected override TestModelBuilder CreateModelBuilder(Action configure = null) + => CreateTestModelBuilder(InMemoryTestHelpers.Instance, configure); } public class InMemoryGenericManyToOne : GenericManyToOne { - protected override TestModelBuilder CreateModelBuilder() - => CreateTestModelBuilder(InMemoryTestHelpers.Instance); + protected override TestModelBuilder CreateModelBuilder(Action configure = null) + => CreateTestModelBuilder(InMemoryTestHelpers.Instance, configure); } public class InMemoryGenericOneToOne : GenericOneToOne @@ -231,14 +231,14 @@ private class Node public Node NextNode { get; set; } } - protected override TestModelBuilder CreateModelBuilder() - => CreateTestModelBuilder(InMemoryTestHelpers.Instance); + protected override TestModelBuilder CreateModelBuilder(Action configure = null) + => CreateTestModelBuilder(InMemoryTestHelpers.Instance, configure); } public class InMemoryGenericOwnedTypes : GenericOwnedTypes { - protected override TestModelBuilder CreateModelBuilder() - => CreateTestModelBuilder(InMemoryTestHelpers.Instance); + protected override TestModelBuilder CreateModelBuilder(Action configure = null) + => CreateTestModelBuilder(InMemoryTestHelpers.Instance, configure); } } } diff --git a/test/EFCore.Relational.Specification.Tests/Migrations/MigrationsInfrastructureTestBase.cs b/test/EFCore.Relational.Specification.Tests/Migrations/MigrationsInfrastructureTestBase.cs index 5579307dda9..816b68b825a 100644 --- a/test/EFCore.Relational.Specification.Tests/Migrations/MigrationsInfrastructureTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Migrations/MigrationsInfrastructureTestBase.cs @@ -5,9 +5,6 @@ using System.Threading.Tasks; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Metadata.Conventions; -using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.TestUtilities; using Microsoft.Extensions.DependencyInjection; diff --git a/test/EFCore.Relational.Specification.Tests/Migrations/MigrationsSqlGeneratorTestBase.cs b/test/EFCore.Relational.Specification.Tests/Migrations/MigrationsSqlGeneratorTestBase.cs index 2a396a03c64..33756d7f201 100644 --- a/test/EFCore.Relational.Specification.Tests/Migrations/MigrationsSqlGeneratorTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Migrations/MigrationsSqlGeneratorTestBase.cs @@ -758,10 +758,6 @@ protected virtual void Generate(Action buildAction, params Migrati MigrationOperation[] operation, MigrationsSqlGenerationOptions options) { - var services = ContextOptions != null - ? TestHelpers.CreateContextServices(CustomServices, ContextOptions) - : TestHelpers.CreateContextServices(CustomServices); - IModel model = null; if (buildAction != null) { @@ -769,10 +765,12 @@ protected virtual void Generate(Action buildAction, params Migrati modelBuilder.Model.RemoveAnnotation(CoreAnnotationNames.ProductVersion); buildAction(modelBuilder); - model = services.GetService().Initialize( - (IModel)modelBuilder.Model, designTime: true, validationLogger: null); + model = modelBuilder.FinalizeModel(designTime: true, skipValidation: true); } + var services = ContextOptions != null + ? TestHelpers.CreateContextServices(CustomServices, ContextOptions) + : TestHelpers.CreateContextServices(CustomServices); var batch = services.GetRequiredService().Generate(operation, model, options); Sql = string.Join( diff --git a/test/EFCore.Relational.Tests/Infrastructure/RelationalModelValidatorTest.PropertyMapping.cs b/test/EFCore.Relational.Tests/Infrastructure/RelationalModelValidatorTest.PropertyMapping.cs new file mode 100644 index 00000000000..b0743f5e032 --- /dev/null +++ b/test/EFCore.Relational.Tests/Infrastructure/RelationalModelValidatorTest.PropertyMapping.cs @@ -0,0 +1,42 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Xunit; + +// ReSharper disable InconsistentNaming +namespace Microsoft.EntityFrameworkCore.Infrastructure +{ + public partial class RelationalModelValidatorTest + { + [ConditionalFact] + public void Throws_when_added_property_is_not_mapped_to_store() + { + var modelBuilder = CreateConventionlessModelBuilder(); + var entityTypeBuilder = modelBuilder.Entity(typeof(NonPrimitiveAsPropertyEntity)); + entityTypeBuilder.Property(typeof(Tuple), "LongProperty"); + entityTypeBuilder.Ignore(nameof(NonPrimitiveAsPropertyEntity.Property)); + + Assert.Equal( + CoreStrings.PropertyNotMapped( + typeof(NonPrimitiveAsPropertyEntity).ShortDisplayName(), "LongProperty", typeof(Tuple).ShortDisplayName()), + Assert.Throws(() => Validate(modelBuilder)).Message); + } + + [ConditionalFact] + public void Throws_when_added_property_is_not_mapped_to_store_even_if_configured_to_use_column_type() + { + var modelBuilder = CreateConventionlessModelBuilder(); + var entityTypeBuilder = modelBuilder.Entity(typeof(NonPrimitiveNonNavigationAsPropertyEntity)); + entityTypeBuilder.Property(typeof(Tuple), "LongProperty") + .HasColumnType("some_int_mapping"); + + Assert.Equal( + CoreStrings.PropertyNotMapped( + typeof(NonPrimitiveNonNavigationAsPropertyEntity).ShortDisplayName(), "LongProperty", + typeof(Tuple).ShortDisplayName()), + Assert.Throws(() => Validate(modelBuilder)).Message); + } + } +} diff --git a/test/EFCore.Relational.Tests/Infrastructure/RelationalModelValidatorTest.cs b/test/EFCore.Relational.Tests/Infrastructure/RelationalModelValidatorTest.cs index fd5c85f7b77..d783ed3cab1 100644 --- a/test/EFCore.Relational.Tests/Infrastructure/RelationalModelValidatorTest.cs +++ b/test/EFCore.Relational.Tests/Infrastructure/RelationalModelValidatorTest.cs @@ -13,19 +13,83 @@ using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Microsoft.EntityFrameworkCore.TestUtilities; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Xunit; // ReSharper disable InconsistentNaming namespace Microsoft.EntityFrameworkCore.Infrastructure { - public class RelationalModelValidatorTest : ModelValidatorTestBase + public partial class RelationalModelValidatorTest : ModelValidatorTest { + public override void Detects_key_property_which_cannot_be_compared() + { + var modelBuilder = CreateConventionalModelBuilder(); + + modelBuilder.Entity(eb => + { + eb.Property(e => e.Id); + eb.HasKey(e => e.Id); + }); + + VerifyError( + CoreStrings.PropertyNotMapped(nameof(WithNonComparableKey), nameof(WithNonComparableKey.Id), nameof(NotComparable)), + modelBuilder); + } + + public override void Detects_unique_index_property_which_cannot_be_compared() + { + var modelBuilder = CreateConventionalModelBuilder(); + + modelBuilder.Entity(eb => + { + eb.HasIndex(e => e.Index).IsUnique(); + }); + + VerifyError( + CoreStrings.PropertyNotMapped( + nameof(WithNonComparableUniqueIndex), nameof(WithNonComparableUniqueIndex.Index), nameof(NotComparable)), + modelBuilder); + } + + public override void Ignores_normal_property_which_cannot_be_compared() + { + var modelBuilder = CreateConventionalModelBuilder(); + + modelBuilder.Entity(eb => + { + eb.Property(e => e.Id); + eb.HasKey(e => e.Id); + eb.Property(e => e.Foo); + }); + + VerifyError( + CoreStrings.PropertyNotMapped( + nameof(WithNonComparableNormalProperty), nameof(WithNonComparableNormalProperty.Foo), nameof(NotComparable)), + modelBuilder); + } + + public override void Detects_missing_discriminator_property() + { + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; + + var entityA = model.AddEntityType(typeof(A)); + SetPrimaryKey(entityA); + AddProperties(entityA); + + var entityC = model.AddEntityType(typeof(C)); + entityC.BaseType = entityA; + + VerifyError(RelationalStrings.NonTPHTableClash( + entityC.DisplayName(), entityA.DisplayName(), entityA.DisplayName()), modelBuilder); + } + [ConditionalFact] public virtual void Ignores_bool_with_default_value_false() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; + var entityType = model.AddEntityType(typeof(E)); SetPrimaryKey(entityType); entityType.AddProperty("ImNot", typeof(bool?)).SetDefaultValue(false); @@ -35,7 +99,7 @@ public virtual void Ignores_bool_with_default_value_false() property.SetDefaultValue(false); property.ValueGenerated = ValueGenerated.OnAdd; - Validate(model); + Validate(modelBuilder); Assert.DoesNotContain(LoggerFactory.Log, l => l.Level == LogLevel.Warning); } @@ -43,7 +107,9 @@ public virtual void Ignores_bool_with_default_value_false() [ConditionalFact] public virtual void Detects_bool_with_default_value_not_false() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; + var entityType = model.AddEntityType(typeof(E)); SetPrimaryKey(entityType); entityType.AddProperty("ImNot", typeof(bool?)).SetDefaultValue(true); @@ -55,13 +121,15 @@ public virtual void Detects_bool_with_default_value_not_false() VerifyWarning( RelationalResources.LogBoolWithDefaultWarning(new TestLogger()) - .GenerateMessage("ImBool", "E"), model); + .GenerateMessage("ImBool", "E"), modelBuilder); } [ConditionalFact] public virtual void Detects_bool_with_default_expression() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; + var entityType = model.AddEntityType(typeof(E)); SetPrimaryKey(entityType); entityType.AddProperty("ImNot", typeof(bool?)).SetDefaultValueSql("TRUE"); @@ -73,13 +141,14 @@ public virtual void Detects_bool_with_default_expression() VerifyWarning( RelationalResources.LogBoolWithDefaultWarning(new TestLogger()) - .GenerateMessage("ImBool", "E"), model); + .GenerateMessage("ImBool", "E"), modelBuilder); } [ConditionalFact] public virtual void Detects_primary_key_with_default_value() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; var entityA = model.AddEntityType(typeof(A)); SetPrimaryKey(entityA); @@ -90,13 +159,14 @@ public virtual void Detects_primary_key_with_default_value() VerifyWarning( RelationalResources.LogKeyHasDefaultValue( - new TestLogger()).GenerateMessage("Id", "A"), model); + new TestLogger()).GenerateMessage("Id", "A"), modelBuilder); } [ConditionalFact] public virtual void Detects_alternate_key_with_default_value() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; var entityA = model.AddEntityType(typeof(A)); SetPrimaryKey(entityA); @@ -111,13 +181,14 @@ public virtual void Detects_alternate_key_with_default_value() VerifyWarning( RelationalResources.LogKeyHasDefaultValue(new TestLogger()).GenerateMessage("P0", "A"), - model); + modelBuilder); } [ConditionalFact] public virtual void Detects_duplicate_table_names_without_identifying_relationship() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; var entityA = model.AddEntityType(typeof(A)); SetPrimaryKey(entityA); @@ -138,13 +209,14 @@ public virtual void Detects_duplicate_table_names_without_identifying_relationsh VerifyError( RelationalStrings.IncompatibleTableNoRelationship( "Schema.Table", entityB.DisplayName(), entityA.DisplayName()), - model); + modelBuilder); } [ConditionalFact] public virtual void Detects_duplicate_table_names_when_no_key() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; var entityA = model.AddEntityType(typeof(A)); entityA.AddProperty("Id", typeof(int)); @@ -165,13 +237,14 @@ public virtual void Detects_duplicate_table_names_when_no_key() VerifyError( RelationalStrings.IncompatibleTableNoRelationship( "Table", entityB.DisplayName(), entityA.DisplayName()), - model); + modelBuilder); } [ConditionalFact] public virtual void Detects_duplicate_view_names_without_identifying_relationship() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; var entityA = model.AddEntityType(typeof(A)); SetPrimaryKey(entityA); @@ -192,13 +265,14 @@ public virtual void Detects_duplicate_view_names_without_identifying_relationshi VerifyError( RelationalStrings.IncompatibleViewNoRelationship( "Schema.Table", entityB.DisplayName(), entityA.DisplayName()), - model); + modelBuilder); } [ConditionalFact] public virtual void Detects_duplicate_view_names_when_no_key() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; var entityA = model.AddEntityType(typeof(A)); entityA.AddProperty("Id", typeof(int)); @@ -219,13 +293,14 @@ public virtual void Detects_duplicate_view_names_when_no_key() VerifyError( RelationalStrings.IncompatibleViewNoRelationship( "Table", entityB.DisplayName(), entityA.DisplayName()), - model); + modelBuilder); } [ConditionalFact] public virtual void Passes_for_duplicate_table_names_in_different_schema() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; var entityA = model.AddEntityType(typeof(A)); SetPrimaryKey(entityA); @@ -242,13 +317,14 @@ public virtual void Passes_for_duplicate_table_names_in_different_schema() entityB.SetTableName("Table"); entityB.SetSchema("SchemaB"); - Validate(model); + Validate(modelBuilder); } [ConditionalFact] public virtual void Passes_for_duplicate_table_names_for_inherited_entities() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; var entityA = model.AddEntityType(typeof(A)); SetPrimaryKey(entityA); @@ -257,7 +333,7 @@ public virtual void Passes_for_duplicate_table_names_for_inherited_entities() var entityC = model.AddEntityType(typeof(C)); SetBaseType(entityC, entityA); - Validate(model); + Validate(modelBuilder); } [ConditionalFact] @@ -273,7 +349,7 @@ public virtual void Detects_incompatible_primary_keys_with_shared_table() VerifyError( RelationalStrings.IncompatibleTableKeyNameMismatch( "Table", nameof(B), nameof(A), "PK_Table", "{'Id'}", "Key", "{'Id'}"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -288,7 +364,7 @@ public virtual void Detects_incompatible_comments_with_shared_table() VerifyError( RelationalStrings.IncompatibleTableCommentMismatch( "Table", nameof(A), nameof(B), "My comment", "my comment"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -300,7 +376,7 @@ public virtual void Passes_on_null_comments() modelBuilder.Entity().ToTable("Table").HasComment("My comment"); modelBuilder.Entity().ToTable("Table"); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalFact] @@ -316,7 +392,7 @@ public virtual void Detects_incompatible_primary_key_columns_with_shared_table() VerifyError( RelationalStrings.DuplicateKeyColumnMismatch( - "{'Id'}", nameof(B), "{'Id'}", nameof(A), "Table", "PK_Table", "{'Id'}", "{'Key'}"), modelBuilder.Model); + "{'Id'}", nameof(B), "{'Id'}", nameof(A), "Table", "PK_Table", "{'Id'}", "{'Key'}"), modelBuilder); } [ConditionalFact] @@ -331,7 +407,7 @@ public virtual void Passes_on_not_configured_shared_columns_with_shared_table() modelBuilder.Entity().Property(b => b.P0).HasColumnName(nameof(A.P0)).HasColumnType("someInt"); modelBuilder.Entity().ToTable("Table"); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalFact] @@ -345,7 +421,7 @@ public virtual void Throws_on_not_configured_shared_columns_with_shared_table_wi modelBuilder.Entity().Property(b => b.P0).HasColumnName(nameof(A.P0)).HasColumnType("someInt"); modelBuilder.Entity().ToTable("Table"); - VerifyError(RelationalStrings.OptionalDependentWithDependentWithoutIdentifyingProperty(nameof(A)), modelBuilder.Model); + VerifyError(RelationalStrings.OptionalDependentWithDependentWithoutIdentifyingProperty(nameof(A)), modelBuilder); } [ConditionalFact] @@ -356,7 +432,7 @@ public virtual void Warns_on_not_configured_shared_columns_with_shared_table() modelBuilder.Entity().OwnsOne(e => e.Owned); var definition = RelationalResources.LogOptionalDependentWithoutIdentifyingProperty(new TestLogger()); - VerifyWarning(definition.GenerateMessage(nameof(OwnedEntity)), modelBuilder.Model); + VerifyWarning(definition.GenerateMessage(nameof(OwnedEntity)), modelBuilder); } [ConditionalFact] @@ -373,7 +449,7 @@ public virtual void Detects_incompatible_shared_columns_with_shared_table() VerifyError( RelationalStrings.DuplicateColumnNameDataTypeMismatch( nameof(A), nameof(A.P0), nameof(B), nameof(B.P0), nameof(B.P0), "Table", "someInt", "default_int_mapping"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -389,7 +465,7 @@ public virtual void Detects_multiple_shared_table_roots() VerifyError( RelationalStrings.IncompatibleTableNoRelationship("Table", nameof(C), nameof(B)), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -404,7 +480,7 @@ public virtual void Detects_shared_table_root_cycle() VerifyError( CoreStrings.IdentifyingRelationshipCycle("A -> B"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -428,7 +504,7 @@ public virtual void Passes_for_compatible_shared_table() .HasName("Key"); }); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalFact] @@ -440,7 +516,7 @@ public virtual void Passes_for_compatible_excluded_shared_table_inverted() modelBuilder.Entity().ToTable("Table", t => t.ExcludeFromMigrations()); modelBuilder.Entity().ToTable("Table", t => t.ExcludeFromMigrations()); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalFact] @@ -451,7 +527,7 @@ public virtual void Passes_for_compatible_excluded_shared_table_owned() modelBuilder.Entity().OwnsOne(b => b.A); modelBuilder.Entity().ToTable("Table", t => t.ExcludeFromMigrations()); - var model = Validate(modelBuilder.Model); + var model = Validate(modelBuilder); var b = model.FindEntityType(typeof(B)); Assert.Equal("Table", b.GetTableName()); @@ -466,7 +542,7 @@ public virtual void Passes_for_compatible_excluded_table_derived() modelBuilder.Entity().ToTable("Table", t => t.ExcludeFromMigrations()); modelBuilder.Entity(); - var model = Validate(modelBuilder.Model); + var model = Validate(modelBuilder); var c = model.FindEntityType(typeof(C)); Assert.Equal("Table", c.GetTableName()); @@ -485,7 +561,7 @@ public virtual void Detect_partially_excluded_shared_table() VerifyError( RelationalStrings.IncompatibleTableExcludedMismatch( nameof(Table), nameof(A), nameof(B)), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -500,7 +576,7 @@ public virtual void Detects_duplicate_column_names() RelationalStrings.DuplicateColumnNameDataTypeMismatch( nameof(Animal), nameof(Animal.Id), nameof(Animal), nameof(Animal.Name), "Name", nameof(Animal), "default_int_mapping", "just_string(max)"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -515,7 +591,7 @@ public virtual void Detects_duplicate_columns_in_derived_types_with_different_ty VerifyError( RelationalStrings.DuplicateColumnNameDataTypeMismatch( nameof(Cat), nameof(Cat.Type), nameof(Dog), nameof(Dog.Type), nameof(Cat.Type), nameof(Animal), "just_string(max)", - "default_int_mapping"), modelBuilder.Model); + "default_int_mapping"), modelBuilder); } [ConditionalFact] @@ -530,7 +606,7 @@ public virtual void Detects_duplicate_column_names_within_hierarchy_with_differe VerifyError( RelationalStrings.DuplicateColumnNameMaxLengthMismatch( nameof(Cat), nameof(Cat.Breed), nameof(Dog), nameof(Dog.Breed), nameof(Cat.Breed), nameof(Animal), "30", - "15"), modelBuilder.Model); + "15"), modelBuilder); } [ConditionalFact] @@ -544,7 +620,7 @@ public virtual void Detects_duplicate_column_names_within_hierarchy_with_differe VerifyError( RelationalStrings.DuplicateColumnNameUnicodenessMismatch( - nameof(Cat), nameof(Cat.Breed), nameof(Dog), nameof(Dog.Breed), nameof(Cat.Breed), nameof(Animal)), modelBuilder.Model); + nameof(Cat), nameof(Cat.Breed), nameof(Dog), nameof(Dog.Breed), nameof(Cat.Breed), nameof(Animal)), modelBuilder); } [ConditionalFact] @@ -558,7 +634,7 @@ public virtual void Detects_duplicate_column_names_within_hierarchy_with_differe VerifyError( RelationalStrings.DuplicateColumnNameFixedLengthMismatch( - nameof(Cat), nameof(Cat.Breed), nameof(Dog), nameof(Dog.Breed), nameof(Cat.Breed), nameof(Animal)), modelBuilder.Model); + nameof(Cat), nameof(Cat.Breed), nameof(Dog), nameof(Dog.Breed), nameof(Cat.Breed), nameof(Animal)), modelBuilder); } [ConditionalFact] @@ -575,7 +651,7 @@ public virtual void Detects_duplicate_column_names_within_hierarchy_with_differe nameof(Cat), nameof(Cat.Breed), nameof(Dog), nameof(Dog.Breed), nameof(Cat.Breed), nameof(Animal)), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -589,7 +665,7 @@ public virtual void Detects_duplicate_column_names_within_hierarchy_with_differe VerifyError( RelationalStrings.DuplicateColumnNameComputedSqlMismatch( nameof(Cat), nameof(Cat.Breed), nameof(Dog), nameof(Dog.Breed), nameof(Cat.Breed), nameof(Animal), "1", ""), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -603,7 +679,7 @@ public virtual void Detects_duplicate_column_names_within_hierarchy_with_differe VerifyError( RelationalStrings.DuplicateColumnNameIsStoredMismatch( nameof(Cat), nameof(Cat.Breed), nameof(Dog), nameof(Dog.Breed), nameof(Cat.Breed), nameof(Animal), "True", ""), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -617,7 +693,7 @@ public virtual void Detects_duplicate_column_names_within_hierarchy_with_differe VerifyError( RelationalStrings.DuplicateColumnNameDefaultSqlMismatch( nameof(Cat), nameof(Cat.Breed), nameof(Dog), nameof(Dog.Breed), nameof(Cat.Breed), nameof(Animal), "NULL", "1"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -631,7 +707,7 @@ public virtual void Detects_duplicate_column_names_within_hierarchy_with_differe VerifyError( RelationalStrings.DuplicateColumnNameDefaultSqlMismatch( nameof(Cat), nameof(Cat.Breed), nameof(Dog), nameof(Dog.Breed), nameof(Cat.Breed), nameof(Animal), "1", ""), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -645,7 +721,7 @@ public virtual void Detects_duplicate_column_names_within_hierarchy_with_differe VerifyError( RelationalStrings.DuplicateColumnNameNullabilityMismatch( nameof(Animal), nameof(Animal.Id), nameof(Dog), "OtherId", nameof(Animal.Id), nameof(Animal)), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -659,7 +735,7 @@ public virtual void Detects_duplicate_column_names_within_hierarchy_with_differe VerifyError( RelationalStrings.DuplicateColumnNameCommentMismatch( nameof(Cat), nameof(Cat.Breed), nameof(Dog), nameof(Dog.Breed), nameof(Cat.Breed), nameof(Animal), "My comment", ""), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -673,7 +749,7 @@ public virtual void Detects_duplicate_column_names_within_hierarchy_with_differe VerifyError( RelationalStrings.DuplicateColumnNameCollationMismatch( nameof(Cat), nameof(Cat.Breed), nameof(Dog), nameof(Dog.Breed), nameof(Cat.Breed), nameof(Animal), "UTF8", ""), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -687,7 +763,7 @@ public virtual void Detects_duplicate_column_names_within_hierarchy_with_differe VerifyError( RelationalStrings.DuplicateColumnNamePrecisionMismatch( nameof(Cat), nameof(Cat.Breed), nameof(Dog), nameof(Dog.Breed), nameof(Cat.Breed), nameof(Animal), "", "1"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -701,7 +777,7 @@ public virtual void Detects_duplicate_column_names_within_hierarchy_with_differe VerifyError( RelationalStrings.DuplicateColumnNameScaleMismatch( nameof(Cat), nameof(Cat.Breed), nameof(Dog), nameof(Dog.Breed), nameof(Cat.Breed), nameof(Animal), "", "2"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -728,7 +804,7 @@ public virtual void Passes_for_compatible_duplicate_column_names_within_hierarch eb.Property("Selected").IsRequired().HasDefaultValue("false").HasConversion(); }); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalFact] @@ -739,7 +815,7 @@ public virtual void Passes_for_shared_columns() modelBuilder.Entity().OwnsOne(a => a.FavoritePerson); modelBuilder.Entity(); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalFact(Skip = "Issue #23144")] @@ -760,7 +836,7 @@ public virtual void Detects_duplicate_foreignKey_names_within_hierarchy_on_diffe "FK", "Cats", "Dogs"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -778,7 +854,7 @@ public virtual void Detects_duplicate_foreignKey_names_within_hierarchy_with_dif nameof(Animal), "FK", nameof(Animal), nameof(Person)), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -798,7 +874,7 @@ public virtual void Detects_duplicate_foreignKey_names_within_hierarchy_with_dif nameof(Animal), "FK", "{'FriendId'}", "{'FriendId', 'Shadow'}"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -837,7 +913,7 @@ public virtual void Detects_duplicate_foreignKey_names_within_hierarchy_with_dif nameof(Animal), "FK", "{'" + nameof(Dog.Breed) + "', '" + nameof(Dog.Name) + "'}", "{'" + nameof(Cat.Name) + "', '" + nameof(Cat.Breed) + "'}"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -860,7 +936,7 @@ public virtual void Detects_duplicate_foreignKey_names_within_hierarchy_mapped_t nameof(Animal), "FK", "{'" + nameof(Dog.Name) + "', 'DogBreed'}", "{'" + nameof(Cat.Name) + "', '" + nameof(Cat.Breed) + "'}"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -883,7 +959,7 @@ public virtual void Detects_duplicate_foreignKey_names_within_hierarchy_referenc nameof(Animal), "FK", "{'" + nameof(Person.FavoriteBreed) + "'}", "{'" + nameof(Person.Name) + "'}"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -902,7 +978,7 @@ public virtual void Detects_duplicate_foreignKey_names_within_hierarchy_with_dif "{'" + nameof(Dog.Name) + "'}", nameof(Dog), "{'" + nameof(Cat.Name) + "'}", nameof(Cat), nameof(Animal), "FK_Animal_Person_Name"), - modelBuilder.Model); + modelBuilder); var index1 = fk1.DeclaringEntityType.GetDeclaredIndexes().Single(); var index2 = fk2.DeclaringEntityType.GetDeclaredIndexes().Single(); @@ -926,7 +1002,7 @@ public virtual void Detects_duplicate_foreignKey_names_within_hierarchy_with_dif "{'" + nameof(Cat.Name) + "'}", nameof(Cat), nameof(Animal), "FK_Animal_Person_Name", DeleteBehavior.SetNull, DeleteBehavior.Cascade), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -939,7 +1015,7 @@ public virtual void Passes_for_incompatible_foreignKeys_within_hierarchy() var fk2 = modelBuilder.Entity().HasOne().WithMany().HasForeignKey(d => d.Name).HasPrincipalKey(p => p.Name) .OnDelete(DeleteBehavior.SetNull).Metadata; - Validate(modelBuilder.Model); + Validate(modelBuilder); Assert.Equal("FK_Animal_Person_Name", fk1.GetConstraintName()); Assert.Equal("FK_Animal_Person_Name1", fk2.GetConstraintName()); @@ -960,7 +1036,7 @@ public virtual void Passes_for_incompatible_foreignKeys_within_hierarchy_when_on var fk2 = modelBuilder.Entity().HasOne().WithMany().HasForeignKey(d => d.Name).HasPrincipalKey(p => p.Name) .OnDelete(DeleteBehavior.SetNull).Metadata; - Validate(modelBuilder.Model); + Validate(modelBuilder); Assert.Equal("FK_Animal_Person_Name", fk1.GetConstraintName()); Assert.Equal("FK_Animal_Person_Name1", fk2.GetConstraintName()); @@ -1006,7 +1082,7 @@ public virtual void Passes_for_compatible_duplicate_foreignKey_names_within_hier .Metadata; }); - Validate(modelBuilder.Model); + Validate(modelBuilder); Assert.NotSame(fk1, fk2); Assert.Equal(fk1.GetConstraintName(), fk2.GetConstraintName()); @@ -1054,7 +1130,7 @@ public virtual void Passes_for_compatible_duplicate_foreignKey_names_within_hier .Metadata; }); - Validate(modelBuilder.Model); + Validate(modelBuilder); Assert.NotSame(fk1, fk2); Assert.Equal(fk1.GetConstraintName(), fk2.GetConstraintName()); @@ -1080,7 +1156,7 @@ public virtual void Detects_duplicate_index_names_within_hierarchy_with_differen nameof(Animal), "IX", "{'" + nameof(Dog.Name) + "'}", "{'" + nameof(Cat.Name) + "', 'Shadow'}"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1111,7 +1187,7 @@ public virtual void Detects_duplicate_index_names_within_hierarchy_with_differen nameof(Animal), "IX", "{'" + nameof(Dog.Breed) + "', '" + nameof(Dog.Name) + "'}", "{'" + nameof(Cat.Name) + "', '" + nameof(Cat.Breed) + "'}"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1132,7 +1208,7 @@ public virtual void Detects_duplicate_index_names_within_hierarchy_mapped_to_dif nameof(Animal), "IX", "{'" + nameof(Dog.Name) + "', 'DogBreed'}", "{'" + nameof(Cat.Name) + "', '" + nameof(Cat.Breed) + "'}"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1148,7 +1224,7 @@ public virtual void Detects_duplicate_index_names_within_hierarchy_with_differen "{'" + nameof(Dog.Name) + "'}", nameof(Dog), "{'" + nameof(Cat.Name) + "'}", nameof(Cat), nameof(Animal), "IX_Animal_Name"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1159,7 +1235,7 @@ public virtual void Passes_for_incompatible_indexes_within_hierarchy_when_one_na var index1 = modelBuilder.Entity().HasIndex(c => c.Name).IsUnique().HasDatabaseName("IX_Animal_Name").Metadata; var index2 = modelBuilder.Entity().HasIndex(d => d.Name).IsUnique(false).Metadata; - Validate(modelBuilder.Model); + Validate(modelBuilder); Assert.Equal("IX_Animal_Name", index1.GetDatabaseName()); Assert.Equal("IX_Animal_Name1", index2.GetDatabaseName()); @@ -1185,7 +1261,7 @@ public virtual void Passes_for_compatible_duplicate_index_names_within_hierarchy index2 = et.HasIndex(c => c.Breed, "IX_Animal_Breed").Metadata; }); - Validate(modelBuilder.Model); + Validate(modelBuilder); Assert.NotSame(index1, index2); Assert.Equal(index1.GetDatabaseName(), index2.GetDatabaseName()); @@ -1198,7 +1274,7 @@ public virtual void Passes_for_indexes_on_related_types_mapped_to_different_tabl modelBuilder.Entity(); modelBuilder.Entity(); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [Table("Objects")] @@ -1243,7 +1319,7 @@ public virtual void Detects_missing_concurrency_token_on_the_base_type_without_c VerifyError( RelationalStrings.MissingConcurrencyColumn(nameof(Animal), "Version", nameof(Animal)), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1256,7 +1332,7 @@ public virtual void Detects_missing_concurrency_token_on_the_sharing_type_withou VerifyError( RelationalStrings.MissingConcurrencyColumn(nameof(Person), "Version", nameof(Animal)), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1269,7 +1345,7 @@ public virtual void Passes_with_missing_concurrency_token_property_on_the_base_t modelBuilder.Entity() .Property("Version").IsRowVersion().HasColumnName("Version"); - var model = Validate(modelBuilder.Model); + var model = Validate(modelBuilder); } [ConditionalFact] @@ -1283,7 +1359,7 @@ public virtual void Passes_with_missing_concurrency_token_property_on_the_base_t modelBuilder.Entity() .Property("Version").IsRowVersion().HasColumnName("Version"); - var model = Validate(modelBuilder.Model); + var model = Validate(modelBuilder); var animalType = model.FindEntityType(typeof(Animal)); Assert.Empty(animalType.GetProperties().Where(p => p.IsConcurrencyToken)); @@ -1297,7 +1373,7 @@ public virtual void Passes_with_missing_concurrency_token_property_on_the_sharin modelBuilder.Entity().HasOne(a => a.FavoritePerson).WithOne().HasForeignKey(p => p.Id); modelBuilder.Entity().Property("Version").IsRowVersion().HasColumnName("Version"); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalFact] @@ -1313,7 +1389,7 @@ public virtual void Passes_for_explicitly_mapped_concurrency_tokens_with_table_s modelBuilder.Entity(); modelBuilder.Entity(); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalFact] @@ -1326,7 +1402,7 @@ public virtual void Passes_for_missing_concurrency_token_on_owner() pb => pb.Property("Version").IsRowVersion().HasColumnName("Version")); modelBuilder.Entity(); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalFact] @@ -1339,19 +1415,20 @@ public virtual void Passes_for_explicitly_mapped_concurrency_tokens_with_owned() pb => pb.Property("Version").IsRowVersion()); modelBuilder.Entity(); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalFact] public virtual void Passes_for_non_hierarchical_model() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; var entityA = model.AddEntityType(typeof(A)); SetPrimaryKey(entityA); AddProperties(entityA); - Validate(model); + Validate(modelBuilder); } [ConditionalFact] @@ -1365,7 +1442,7 @@ public virtual void Passes_for_missing_discriminator_value_for_abstract_class() .HasValue(2) .HasValue>(3); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalFact] @@ -1375,7 +1452,7 @@ public virtual void Passes_for_TPT() modelBuilder.Entity(); modelBuilder.Entity().ToTable("Cat").ToView("Cat"); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalFact] @@ -1388,7 +1465,7 @@ public virtual void Detects_unconfigured_entity_type_in_TPT() VerifyError( RelationalStrings.NonTPHTableClash(nameof(Dog), nameof(Animal), nameof(Animal)), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1401,7 +1478,7 @@ public virtual void Detects_clashing_entity_types_in_view_TPT() VerifyError( RelationalStrings.NonTPHViewClash(nameof(Dog), nameof(Cat), "Cat"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1413,7 +1490,7 @@ public virtual void Detects_table_and_view_TPT_mismatch() VerifyError( RelationalStrings.NonTPHTableClash(nameof(Cat), nameof(Animal), "Animal"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1425,7 +1502,7 @@ public virtual void Detects_TPT_with_discriminator() VerifyError( RelationalStrings.TPHTableMismatch(nameof(Cat), nameof(Cat), nameof(Animal), nameof(Animal)), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1437,7 +1514,7 @@ public virtual void Detects_view_TPT_with_discriminator() VerifyError( RelationalStrings.TPHViewMismatch(nameof(Cat), nameof(Cat), nameof(Animal), nameof(Animal)), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1457,7 +1534,7 @@ public virtual void Passes_on_valid_table_sharing_with_TPT() modelBuilder.Entity().ToTable("Cat"); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalFact] @@ -1480,7 +1557,7 @@ public virtual void Detects_linking_relationship_on_derived_type_in_TPT() VerifyError( RelationalStrings.IncompatibleTableDerivedRelationship( "Cat", "Cat", "Person"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1504,7 +1581,7 @@ public virtual void Detects_linking_relationship_on_derived_type_in_TPT_views() VerifyError( RelationalStrings.IncompatibleViewDerivedRelationship( "Cat", "Cat", "Person"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1524,7 +1601,7 @@ public virtual void Detects_unmapped_foreign_keys_in_TPT() definition.EventId, definition.MessageFormat, "{'FavoritePersonId'}", nameof(Cat), nameof(Person), "{'FavoritePersonId'}", nameof(Cat), "{'Id'}", nameof(Person))), - modelBuilder.Model, + modelBuilder, LogLevel.Error); } @@ -1536,7 +1613,7 @@ public virtual void Passes_for_valid_table_overrides() modelBuilder.Entity().ToTable("Dog"); property.HasColumnName("DogName", StoreObjectIdentifier.Table("Dog", null)); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalFact] @@ -1548,7 +1625,7 @@ public virtual void Detects_invalid_table_overrides() VerifyError( RelationalStrings.TableOverrideMismatch("Animal.Name", "Dog"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1559,7 +1636,7 @@ public virtual void Passes_for_valid_view_overrides() modelBuilder.Entity().ToView("Dog"); property.HasColumnName("DogName", StoreObjectIdentifier.View("Dog", null)); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalFact] @@ -1571,7 +1648,7 @@ public virtual void Detects_invalid_view_overrides() VerifyError( RelationalStrings.ViewOverrideMismatch("Animal.Name", "Dog"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1583,7 +1660,7 @@ public virtual void Detects_invalid_sql_query_overrides() VerifyError( RelationalStrings.SqlQueryOverrideMismatch("Animal.Name", "Dog"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1595,7 +1672,7 @@ public virtual void Detects_invalid_function_overrides() VerifyError( RelationalStrings.FunctionOverrideMismatch("Animal.Name", "Dog"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1609,7 +1686,7 @@ public void Detects_function_with_invalid_return_type() RelationalStrings.DbFunctionInvalidReturnType( "Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidatorTest+TestMethods.MethodC()", typeof(TestMethods).ShortDisplayName()), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1628,7 +1705,7 @@ var methodInfo "Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidatorTest+TestMethods.MethodA()", typeof(IQueryable).ShortDisplayName(), typeof(TestMethods).ShortDisplayName()), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1643,7 +1720,7 @@ public void Detects_function_with_invalid_parameter_type() "methods", "Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidatorTest+TestMethods.MethodD(Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidatorTest+TestMethods)", typeof(TestMethods).ShortDisplayName()), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1659,7 +1736,7 @@ var methodInfo modelBuilder.Entity().HasNoKey().ToFunction(function.ModelName); - var model = Validate(modelBuilder.Model); + var model = Validate(modelBuilder); Assert.Single(model.GetEntityTypes()); Assert.Single(model.GetDbFunctions()); @@ -1676,7 +1753,7 @@ public void Detects_entity_type_mapped_to_non_existent_function() VerifyError( RelationalStrings.MappedFunctionNotFound(nameof(TestMethods), "NonExistent"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1694,7 +1771,7 @@ public void Detects_entity_type_mapped_to_a_scalar_function() "Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidatorTest+TestMethods.MethodE()", "int", nameof(TestMethods)), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1713,7 +1790,7 @@ public void Detects_entity_type_mapped_to_a_different_type() "Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidatorTest+TestMethods.MethodA()", typeof(IQueryable).ShortDisplayName(), nameof(Animal)), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1730,7 +1807,7 @@ public void Detects_entity_type_mapped_to_a_function_with_parameters() nameof(TestMethods), "Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidatorTest+TestMethods.MethodB(int)", "{'id'}"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1752,7 +1829,7 @@ public void Detects_multiple_entity_types_mapped_to_the_same_function() RelationalStrings.DbFunctionInvalidIQueryableOwnedReturnType( "Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidatorTest+TestMethods.MethodA()", nameof(TestMethods)), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1770,7 +1847,7 @@ public void Detects_derived_entity_type_mapped_to_a_function() nameof(TestMethods), "Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidatorTest+TestMethods.MethodA()", nameof(BaseTestMethods)), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1788,7 +1865,7 @@ public void Passes_for_unnamed_index_with_all_properties_not_mapped_to_any_table definition.GenerateMessage( nameof(Animal), "{'Id', 'Name'}"), - modelBuilder.Model, + modelBuilder, LogLevel.Information); } @@ -1811,7 +1888,7 @@ public void Passes_for_named_index_with_all_properties_not_mapped_to_any_table() "IX_AllPropertiesNotMapped", nameof(Animal), "{'Id', 'Name'}"), - modelBuilder.Model, + modelBuilder, LogLevel.Information); } @@ -1832,7 +1909,7 @@ public void Detects_mix_of_index_property_mapped_and_not_mapped_to_any_table_unm nameof(Cat), "{'Name', 'Identity'}", "Name"), - modelBuilder.Model, + modelBuilder, LogLevel.Error); } @@ -1857,7 +1934,7 @@ public void Detects_mix_of_index_property_mapped_and_not_mapped_to_any_table_map nameof(Cat), "{'Identity', 'Name'}", "Name"), - modelBuilder.Model, + modelBuilder, LogLevel.Error); } @@ -1870,7 +1947,7 @@ public void Passes_for_index_properties_mapped_to_same_table_in_TPT_hierarchy() modelBuilder.Entity().ToTable("Cats"); modelBuilder.Entity().HasIndex(nameof(Animal.Id), nameof(Cat.Identity)); - Validate(modelBuilder.Model); + Validate(modelBuilder); Assert.Empty( LoggerFactory.Log @@ -1897,7 +1974,7 @@ public void Detects_unnamed_index_properties_mapped_to_different_tables_in_TPT_h "{'Animals'}", nameof(Cat.Identity), "{'Cats'}"), - modelBuilder.Model, + modelBuilder, LogLevel.Error); } @@ -1929,7 +2006,7 @@ public void Detects_named_index_properties_mapped_to_different_tables_in_TPT_hie "{'Animals'}", nameof(Cat.Identity), "{'Cats'}")), - modelBuilder.Model, + modelBuilder, LogLevel.Error); } @@ -1944,7 +2021,7 @@ public virtual void Non_TPH_as_a_result_of_DbFunction_throws() VerifyError( RelationalStrings.TableValuedFunctionNonTPH( - TestMethods.MethodFMi.DeclaringType.FullName + "." + TestMethods.MethodFMi.Name + "()", "C"), modelBuilder.Model); + TestMethods.MethodFMi.DeclaringType.FullName + "." + TestMethods.MethodFMi.Name + "()", "C"), modelBuilder); } [ConditionalFact] @@ -1958,7 +2035,7 @@ public virtual void Passes_for_relational_override_without_inheritance() e.Property(p => p.Name).Metadata.SetColumnName("bar", StoreObjectIdentifier.Table("foo", null)); }); - Validate(modelBuilder.Model); + Validate(modelBuilder); Assert.DoesNotContain(LoggerFactory.Log, l => l.Level == LogLevel.Warning); } @@ -2083,18 +2160,12 @@ public static IQueryable MethodF() => throw new NotImplementedException(); } - protected virtual ModelBuilder CreateModelBuilderWithoutConvention( - bool sensitiveDataLoggingEnabled = false) - { - var conventionSet = TestHelpers.CreateConventionalConventionSet( - CreateModelLogger(sensitiveDataLoggingEnabled), CreateValidationLogger(sensitiveDataLoggingEnabled)); - - ConventionSet.Remove( - conventionSet.ModelFinalizingConventions, - typeof(T)); - - return new ModelBuilder(conventionSet); - } + protected virtual TestHelpers.TestModelBuilder CreateModelBuilderWithoutConvention(bool sensitiveDataLoggingEnabled = false) + => TestHelpers.CreateConventionBuilder( + CreateModelLogger(sensitiveDataLoggingEnabled), CreateValidationLogger(sensitiveDataLoggingEnabled), + modelConfigurationBuilder => ConventionSet.Remove( + modelConfigurationBuilder.Conventions.ModelFinalizingConventions, + typeof(T))); protected override TestHelpers TestHelpers => RelationalTestHelpers.Instance; diff --git a/test/EFCore.Relational.Tests/Metadata/Conventions/Internal/TableValuedDbFunctionConventionTest.cs b/test/EFCore.Relational.Tests/Metadata/Conventions/Internal/TableValuedDbFunctionConventionTest.cs index 054ac7b6d30..3fd6e7cdf5e 100644 --- a/test/EFCore.Relational.Tests/Metadata/Conventions/Internal/TableValuedDbFunctionConventionTest.cs +++ b/test/EFCore.Relational.Tests/Metadata/Conventions/Internal/TableValuedDbFunctionConventionTest.cs @@ -101,11 +101,11 @@ public void Throws_when_adding_a_function_returning_a_scalar() Assert.Throws(() => Finalize(modelBuilder)).Message); } - private static ModelBuilder CreateModelBuilder() + private static TestHelpers.TestModelBuilder CreateModelBuilder() => RelationalTestHelpers.Instance.CreateConventionBuilder(); - private static IModel Finalize(ModelBuilder modelBuilder) - => RelationalTestHelpers.Instance.Finalize(modelBuilder); + private static IModel Finalize(TestHelpers.TestModelBuilder modelBuilder) + => modelBuilder.FinalizeModel(); private static IQueryable GetEntities(int id) => throw new NotImplementedException(); diff --git a/test/EFCore.Relational.Tests/Metadata/DbFunctionMetadataTests.cs b/test/EFCore.Relational.Tests/Metadata/DbFunctionMetadataTests.cs index 1fe99629596..7f548230123 100644 --- a/test/EFCore.Relational.Tests/Metadata/DbFunctionMetadataTests.cs +++ b/test/EFCore.Relational.Tests/Metadata/DbFunctionMetadataTests.cs @@ -7,12 +7,11 @@ using System.Reflection; using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Infrastructure.Internal; using Microsoft.EntityFrameworkCore.Internal; -using Microsoft.EntityFrameworkCore.Metadata.Conventions; using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure; using Microsoft.EntityFrameworkCore.Query.SqlExpressions; using Microsoft.EntityFrameworkCore.TestUtilities; +using Microsoft.EntityFrameworkCore.TestUtilities.FakeProvider; using Microsoft.Extensions.DependencyInjection; using Xunit; @@ -44,6 +43,11 @@ public static int DuplicateNameTest() protected class MyBaseContext : DbContext { + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + optionsBuilder.UseFakeRelational(); + } + public static readonly string[] FunctionNames = { nameof(StaticPublicBase), @@ -117,6 +121,11 @@ public virtual int VirtualBase() protected class MyDerivedContext : MyBaseContext { + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().HasNoKey(); + } + public static new readonly string[] FunctionNames = { nameof(StaticPublicDerived), @@ -325,8 +334,7 @@ var dup2methodInfo [ConditionalFact] public virtual void Finds_DbFunctions_on_DbContext() { - var model = RelationalTestHelpers.Instance.CreateContextServices().GetRequiredService() - .Initialize(GetModelBuilder(new MyDerivedContext()).FinalizeModel(), designTime: false, validationLogger: null); + var model = new MyDerivedContext().Model; foreach (var function in MyBaseContext.FunctionNames) { @@ -547,7 +555,7 @@ public void Adding_method_with_store_type() var dbFuncBuilder = modelBuilder.HasDbFunction(MethodAmi).HasStoreType("int(8)"); - modelBuilder.FinalizeModel(); + modelBuilder.FinalizeModel(skipValidation: true); Assert.Equal("int(8)", dbFuncBuilder.Metadata.StoreType); } @@ -679,8 +687,7 @@ var queryableNoParams var functionName = modelBuilder.HasDbFunction(queryableNoParams).Metadata.ModelName; - var model = RelationalTestHelpers.Instance.CreateContextServices().GetRequiredService() - .Initialize(modelBuilder.FinalizeModel(), designTime: false, validationLogger: null); + var model = modelBuilder.FinalizeModel(skipValidation: true); var function = model.FindDbFunction(functionName); var entityType = model.FindEntityType(typeof(Foo)); @@ -805,7 +812,7 @@ public void DbParameters_StoreType() dbFuncBuilder.HasParameter("c").HasStoreType("varchar(max)"); - modelBuilder.FinalizeModel(); + modelBuilder.FinalizeModel(skipValidation: true); Assert.Equal(2, dbFunc.Parameters.Count); @@ -860,24 +867,8 @@ public void DbFunction_Queryable_custom_translation() () => dbFunction.Translation = args => new SqlFragmentExpression("Empty")).Message); } - private ModelBuilder GetModelBuilder(DbContext dbContext = null) - { - if (dbContext == null) - { - return RelationalTestHelpers.Instance.CreateConventionBuilder(); - } - - var conventionSet = new ConventionSet(); - - var dependencies = CreateDependencies().With(new CurrentDbContext(dbContext)); - var relationalDependencies = CreateRelationalDependencies(); - var dbFunctionAttributeConvention = new RelationalDbFunctionAttributeConvention(dependencies, relationalDependencies); - conventionSet.ModelInitializedConventions.Add(dbFunctionAttributeConvention); - conventionSet.ModelFinalizingConventions.Add(dbFunctionAttributeConvention); - conventionSet.ModelFinalizingConventions.Add(new TableValuedDbFunctionConvention(dependencies, relationalDependencies)); - - return new ModelBuilder(conventionSet); - } + private TestHelpers.TestModelBuilder GetModelBuilder() + => RelationalTestHelpers.Instance.CreateConventionBuilder(); private ProviderConventionSetBuilderDependencies CreateDependencies() => RelationalTestHelpers.Instance.CreateContextServices().GetRequiredService(); diff --git a/test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs b/test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs index 3829a84556c..7e90661cbf9 100644 --- a/test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs +++ b/test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs @@ -907,10 +907,10 @@ public void Can_use_relational_model_with_functions() Assert.Equal(tvfDbFunction.Parameters.Single().Name, tvfFunction.Parameters.Single().DbFunctionParameters.Single().Name); } - private static IRelationalModel Finalize(ModelBuilder modelBuilder) - => RelationalTestHelpers.Instance.Finalize(modelBuilder, designTime: true).GetRelationalModel(); + private static IRelationalModel Finalize(TestHelpers.TestModelBuilder modelBuilder) + => modelBuilder.FinalizeModel(designTime: true).GetRelationalModel(); - protected virtual ModelBuilder CreateConventionModelBuilder() + protected virtual TestHelpers.TestModelBuilder CreateConventionModelBuilder() => RelationalTestHelpers.Instance.CreateConventionBuilder(); public enum Mapping diff --git a/test/EFCore.Relational.Tests/Migrations/Internal/MigrationsModelDifferTestBase.cs b/test/EFCore.Relational.Tests/Migrations/Internal/MigrationsModelDifferTestBase.cs index 01643163d55..44551930017 100644 --- a/test/EFCore.Relational.Tests/Migrations/Internal/MigrationsModelDifferTestBase.cs +++ b/test/EFCore.Relational.Tests/Migrations/Internal/MigrationsModelDifferTestBase.cs @@ -5,9 +5,6 @@ using System.Collections.Generic; using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Metadata.Conventions; -using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.TestUtilities; @@ -58,16 +55,14 @@ public abstract class MigrationsModelDifferTestBase var sourceModelBuilder = CreateModelBuilder(skipSourceConventions); buildCommonAction(sourceModelBuilder); buildSourceAction(sourceModelBuilder); - var sourceModel = (IModel)sourceModelBuilder.Model; - var sourceOptionsBuilder = TestHelpers - .AddProviderOptions(new DbContextOptionsBuilder()) - .UseModel(sourceModel) - .EnableSensitiveDataLogging(); var targetModelBuilder = CreateModelBuilder(skipConventions: false); buildCommonAction(targetModelBuilder); buildTargetAction(targetModelBuilder); - var targetModel = (IModel)targetModelBuilder.Model; + + var sourceModel = sourceModelBuilder.FinalizeModel(designTime: true, skipValidation: true); + var targetModel = targetModelBuilder.FinalizeModel(designTime: true, skipValidation: true); + var targetOptionsBuilder = TestHelpers .AddProviderOptions(new DbContextOptionsBuilder()) .UseModel(targetModel) @@ -75,14 +70,8 @@ public abstract class MigrationsModelDifferTestBase if (builderOptionsAction != null) { - builderOptionsAction(sourceOptionsBuilder); builderOptionsAction(targetOptionsBuilder); } - - var modelRuntimeInitializer = TestHelpers.CreateContextServices().GetService(); - sourceModel = modelRuntimeInitializer.Initialize(sourceModel, designTime: true, validationLogger: null); - targetModel = modelRuntimeInitializer.Initialize(targetModel, designTime: true, validationLogger: null); - var modelDiffer = CreateModelDiffer(targetOptionsBuilder.Options); var operationsUp = modelDiffer.GetDifferences(sourceModel.GetRelationalModel(), targetModel.GetRelationalModel()); @@ -147,10 +136,8 @@ protected static T[][] ToJaggedArray(T[,] twoDimensionalArray, bool firstDime protected abstract TestHelpers TestHelpers { get; } - protected virtual ModelBuilder CreateModelBuilder(bool skipConventions) - => skipConventions - ? new ModelBuilder(new ConventionSet()) - : TestHelpers.CreateConventionBuilder(); + protected virtual TestHelpers.TestModelBuilder CreateModelBuilder(bool skipConventions) + => TestHelpers.CreateConventionBuilder(configure: skipConventions ? c => c.RemoveAllConventions() : null); protected virtual MigrationsModelDiffer CreateModelDiffer(DbContextOptions options) { diff --git a/test/EFCore.Relational.Tests/Storage/RelationalParameterBuilderTest.cs b/test/EFCore.Relational.Tests/Storage/RelationalParameterBuilderTest.cs index 7401228e9dc..751d8e513a6 100644 --- a/test/EFCore.Relational.Tests/Storage/RelationalParameterBuilderTest.cs +++ b/test/EFCore.Relational.Tests/Storage/RelationalParameterBuilderTest.cs @@ -3,12 +3,10 @@ using System.Collections.Generic; using System.Data; -using Microsoft.EntityFrameworkCore.Infrastructure; +using System.Linq; using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.EntityFrameworkCore.Storage.Internal; using Microsoft.EntityFrameworkCore.TestUtilities; -using Microsoft.Extensions.DependencyInjection; using Xunit; namespace Microsoft.EntityFrameworkCore.Storage @@ -79,12 +77,13 @@ public void Can_add_type_mapped_parameter_by_property(bool nullable) TestServiceFactory.Instance.Create(), TestServiceFactory.Instance.Create()); - var model = (IMutableModel)new Model(); - var property = model.AddEntityType("MyType").AddProperty("MyProp", typeof(string)); - property.IsNullable = nullable; + var modelBuilder = RelationalTestHelpers.Instance.CreateConventionBuilder(); - RelationalTestHelpers.Instance.CreateContextServices().GetRequiredService() - .Initialize(model.FinalizeModel(), designTime: false, validationLogger: null); + modelBuilder.Entity("MyType").Property("MyProp").IsRequired(!nullable); + + var model = modelBuilder.FinalizeModel(designTime: false, skipValidation: true); + + var property = model.GetEntityTypes().Single().FindProperty("MyProp"); var parameterBuilder = new RelationalCommandBuilder( new RelationalCommandBuilderDependencies(typeMapper)); diff --git a/test/EFCore.Relational.Tests/Update/ModificationCommandComparerTest.cs b/test/EFCore.Relational.Tests/Update/ModificationCommandComparerTest.cs index e19a862c104..7df9e5fd0b7 100644 --- a/test/EFCore.Relational.Tests/Update/ModificationCommandComparerTest.cs +++ b/test/EFCore.Relational.Tests/Update/ModificationCommandComparerTest.cs @@ -19,14 +19,14 @@ public class ModificationCommandComparerTest [ConditionalFact] public void Compare_returns_0_only_for_commands_that_are_equal() { - var modelBuilder = new ModelBuilder(TestRelationalConventionSetBuilder.Build()); + var modelBuilder = RelationalTestHelpers.Instance.CreateConventionBuilder(); var model = modelBuilder.Model; var entityType = model.AddEntityType(typeof(object)); var key = entityType.AddProperty("Id", typeof(int)); entityType.SetPrimaryKey(key); var optionsBuilder = new DbContextOptionsBuilder() - .UseModel(RelationalTestHelpers.Instance.Finalize(modelBuilder)) + .UseModel(modelBuilder.FinalizeModel()) .UseInMemoryDatabase(Guid.NewGuid().ToString()) .UseInternalServiceProvider(InMemoryFixture.DefaultServiceProvider); @@ -160,7 +160,7 @@ public void Compare_returns_0_only_for_entries_that_have_same_key_values() private void Compare_returns_0_only_for_entries_that_have_same_key_values_generic(T value1, T value2) { - var modelBuilder = new ModelBuilder(TestRelationalConventionSetBuilder.Build()); + var modelBuilder = RelationalTestHelpers.Instance.CreateConventionBuilder(); var model = modelBuilder.Model; var entityType = model.AddEntityType(typeof(object)); @@ -170,7 +170,7 @@ private void Compare_returns_0_only_for_entries_that_have_same_key_values_generi var optionsBuilder = new DbContextOptionsBuilder() .UseInternalServiceProvider(InMemoryFixture.DefaultServiceProvider) - .UseModel(RelationalTestHelpers.Instance.Finalize(modelBuilder)) + .UseModel(modelBuilder.FinalizeModel()) .UseInMemoryDatabase(Guid.NewGuid().ToString()); var stateManager = new DbContext(optionsBuilder.Options).GetService(); diff --git a/test/EFCore.Relational.Tests/Update/ModificationCommandTest.cs b/test/EFCore.Relational.Tests/Update/ModificationCommandTest.cs index 69ca5f597cc..18a5018d6e2 100644 --- a/test/EFCore.Relational.Tests/Update/ModificationCommandTest.cs +++ b/test/EFCore.Relational.Tests/Update/ModificationCommandTest.cs @@ -448,7 +448,8 @@ private class T1 private static IModel BuildModel(bool generateKeyValues, bool computeNonKeyValue) { - IMutableModel model = new Model(TestRelationalConventionSetBuilder.Build()); + var modelBuilder = RelationalTestHelpers.Instance.CreateConventionBuilder(); + var model = modelBuilder.Model; var entityType = model.AddEntityType(typeof(T1)); var key = entityType.FindProperty("Id"); @@ -468,7 +469,7 @@ private static IModel BuildModel(bool generateKeyValues, bool computeNonKeyValue nonKey2.SetColumnName("Col3"); nonKey2.ValueGenerated = computeNonKeyValue ? ValueGenerated.OnUpdate : ValueGenerated.Never; - return model.FinalizeModel(); + return modelBuilder.FinalizeModel(); } private static InternalEntityEntry CreateEntry( diff --git a/test/EFCore.Specification.Tests/F1FixtureBase.cs b/test/EFCore.Specification.Tests/F1FixtureBase.cs index 97a3830ab31..31cc37e0767 100644 --- a/test/EFCore.Specification.Tests/F1FixtureBase.cs +++ b/test/EFCore.Specification.Tests/F1FixtureBase.cs @@ -32,7 +32,7 @@ private IModel CreateModelExternal() BuildModelExternal(builder); - return builder.FinalizeModel(); + return (IModel)builder.Model; } public abstract TestHelpers TestHelpers { get; } diff --git a/test/EFCore.Specification.Tests/OptimisticConcurrencyTestBase.cs b/test/EFCore.Specification.Tests/OptimisticConcurrencyTestBase.cs index 46e7bc27470..8ab96bd8096 100644 --- a/test/EFCore.Specification.Tests/OptimisticConcurrencyTestBase.cs +++ b/test/EFCore.Specification.Tests/OptimisticConcurrencyTestBase.cs @@ -7,6 +7,7 @@ using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.TestModels.ConcurrencyModel; using Microsoft.Extensions.Logging; @@ -32,9 +33,8 @@ public virtual void External_model_builder_uses_validation() { var modelBuilder = Fixture.CreateModelBuilder(); modelBuilder.Entity("Dummy"); - var model = modelBuilder.FinalizeModel(); - var context = new F1Context(new DbContextOptionsBuilder(Fixture.CreateOptions()).UseModel(model).Options); + var context = new F1Context(new DbContextOptionsBuilder(Fixture.CreateOptions()).UseModel((IModel)modelBuilder.Model).Options); Assert.Equal( CoreStrings.EntityRequiresKey("Dummy (Dictionary)"), diff --git a/test/EFCore.Specification.Tests/TestUtilities/TestHelpers.cs b/test/EFCore.Specification.Tests/TestUtilities/TestHelpers.cs index 23f74e814a9..d82ef3df463 100644 --- a/test/EFCore.Specification.Tests/TestUtilities/TestHelpers.cs +++ b/test/EFCore.Specification.Tests/TestUtilities/TestHelpers.cs @@ -12,6 +12,7 @@ using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Metadata.Conventions; using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -127,46 +128,37 @@ public IServiceProvider CreateContextServices(IServiceCollection customServices, public IServiceProvider CreateContextServices(IServiceCollection customServices) => ((IInfrastructure)CreateContext(customServices)).Instance; - public IModel Finalize(ModelBuilder modelBuilder, bool designTime = false, bool skipValidation = false) + public TestModelBuilder CreateConventionBuilder( + IDiagnosticsLogger modelLogger = null, + IDiagnosticsLogger validationLogger = null, + Action configure = null, + IServiceCollection customServices = null) { - var contextServices = CreateContextServices(); + customServices ??= new ServiceCollection(); + if (modelLogger != null) + { + customServices.AddScoped(_ => modelLogger); + } - var modelRuntimeInitializer = contextServices.GetRequiredService(); - return modelRuntimeInitializer.Initialize((IModel)modelBuilder.Model, designTime, skipValidation - ? null - : new TestLogger(LoggingDefinitions)); - } + if (validationLogger == null) + { + validationLogger = new TestLogger(LoggingDefinitions); + } - public ModelBuilder CreateConventionBuilder() - => new ModelBuilder(CreateConventionSetBuilder().CreateConventionSet()); + customServices.AddScoped(_ => validationLogger); - public virtual IConventionSetBuilder CreateConventionSetBuilder() - => CreateContextServices().GetRequiredService(); + var contextServices = CreateContextServices(customServices); + var modelCreationDependencies = contextServices.GetRequiredService(); - public ModelBuilder CreateConventionBuilder( - DiagnosticsLogger modelLogger, - DiagnosticsLogger validationLogger) - { - var contextServices = CreateContextServices( - new ServiceCollection() - .AddScoped>(_ => modelLogger) - .AddScoped>(_ => validationLogger)); - - return new ModelBuilder( - contextServices.GetRequiredService().CreateConventionSet(), - contextServices.GetRequiredService() with { Logger = modelLogger }); - } + var modelConfigurationBuilder = new TestModelConfigurationBuilder( + modelCreationDependencies.ConventionSetBuilder.CreateConventionSet()); - public ConventionSet CreateConventionalConventionSet( - DiagnosticsLogger modelLogger, - DiagnosticsLogger validationLogger) - { - var contextServices = CreateContextServices( - new ServiceCollection() - .AddScoped>(_ => modelLogger) - .AddScoped>(_ => validationLogger)); + configure?.Invoke(modelConfigurationBuilder); - return contextServices.GetRequiredService().CreateConventionSet(); + return modelConfigurationBuilder.CreateModelBuilder( + modelCreationDependencies.ModelDependencies, + modelCreationDependencies.ModelRuntimeInitializer, + validationLogger); } public virtual LoggingDefinitions LoggingDefinitions { get; } = new TestLoggingDefinitions(); @@ -345,5 +337,94 @@ private static int AssertResults(IList expected, IList actual) await nestedTestOperation3(innerContext3); }); } + + public class TestModelBuilder : ModelBuilder + { + private readonly IModelRuntimeInitializer _modelRuntimeInitializer; + private readonly IDiagnosticsLogger _validationLogger; + + public TestModelBuilder( + ConventionSet conventions, + ModelDependencies modelDependencies, + ModelConfiguration modelConfiguration, + IModelRuntimeInitializer modelRuntimeInitializer, + IDiagnosticsLogger validationLogger) + : base(conventions, modelDependencies, modelConfiguration) + { + _modelRuntimeInitializer = modelRuntimeInitializer; + _validationLogger = validationLogger; + } + + public override IModel FinalizeModel() + => FinalizeModel(designTime: false); + + public IModel FinalizeModel(bool designTime = false, bool skipValidation = false) + => _modelRuntimeInitializer.Initialize((IModel)Model, designTime, skipValidation ? null : _validationLogger); + } + + public class TestModelConfigurationBuilder : ModelConfigurationBuilder + { + public TestModelConfigurationBuilder(ConventionSet conventions) + : base(conventions) + { + Conventions = conventions; + } + + public ConventionSet Conventions { get; } + + public TestModelBuilder CreateModelBuilder( + ModelDependencies modelDependencies, + IModelRuntimeInitializer modelRuntimeInitializer, + IDiagnosticsLogger validationLogger) + => new(Conventions, + modelDependencies, + ModelConfiguration.IsEmpty() ? null : ModelConfiguration, + modelRuntimeInitializer, + validationLogger); + + public void RemoveAllConventions() + { + Conventions.EntityTypeAddedConventions.Clear(); + Conventions.EntityTypeAnnotationChangedConventions.Clear(); + Conventions.EntityTypeBaseTypeChangedConventions.Clear(); + Conventions.EntityTypeIgnoredConventions.Clear(); + Conventions.EntityTypeMemberIgnoredConventions.Clear(); + Conventions.EntityTypePrimaryKeyChangedConventions.Clear(); + Conventions.EntityTypeRemovedConventions.Clear(); + Conventions.ForeignKeyAddedConventions.Clear(); + Conventions.ForeignKeyAnnotationChangedConventions.Clear(); + Conventions.ForeignKeyDependentRequirednessChangedConventions.Clear(); + Conventions.ForeignKeyOwnershipChangedConventions.Clear(); + Conventions.ForeignKeyPrincipalEndChangedConventions.Clear(); + Conventions.ForeignKeyPropertiesChangedConventions.Clear(); + Conventions.ForeignKeyRemovedConventions.Clear(); + Conventions.ForeignKeyRequirednessChangedConventions.Clear(); + Conventions.ForeignKeyUniquenessChangedConventions.Clear(); + Conventions.IndexAddedConventions.Clear(); + Conventions.IndexAnnotationChangedConventions.Clear(); + Conventions.IndexRemovedConventions.Clear(); + Conventions.IndexUniquenessChangedConventions.Clear(); + Conventions.KeyAddedConventions.Clear(); + Conventions.KeyAnnotationChangedConventions.Clear(); + Conventions.KeyRemovedConventions.Clear(); + Conventions.ModelAnnotationChangedConventions.Clear(); + Conventions.ModelFinalizedConventions.Clear(); + Conventions.ModelFinalizingConventions.Clear(); + Conventions.ModelInitializedConventions.Clear(); + Conventions.NavigationAddedConventions.Clear(); + Conventions.NavigationAnnotationChangedConventions.Clear(); + Conventions.NavigationRemovedConventions.Clear(); + Conventions.PropertyAddedConventions.Clear(); + Conventions.PropertyAnnotationChangedConventions.Clear(); + Conventions.PropertyFieldChangedConventions.Clear(); + Conventions.PropertyNullabilityChangedConventions.Clear(); + Conventions.PropertyRemovedConventions.Clear(); + Conventions.SkipNavigationAddedConventions.Clear(); + Conventions.SkipNavigationAnnotationChangedConventions.Clear(); + Conventions.SkipNavigationForeignKeyChangedConventions.Clear(); + Conventions.SkipNavigationInverseChangedConventions.Clear(); + Conventions.SkipNavigationRemovedConventions.Clear(); + } + } } } diff --git a/test/EFCore.Specification.Tests/ValueConvertersEndToEndTestBase.cs b/test/EFCore.Specification.Tests/ValueConvertersEndToEndTestBase.cs index af842215819..9f73b87fcb9 100644 --- a/test/EFCore.Specification.Tests/ValueConvertersEndToEndTestBase.cs +++ b/test/EFCore.Specification.Tests/ValueConvertersEndToEndTestBase.cs @@ -631,9 +631,9 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con b.Property(e => e.NullableIntAsNullableLong).HasConversion(new CastingConverter()); b.Property(e => e.BytesAsString).HasConversion( - (ValueConverter?)new BytesToStringConverter(), new ArrayStructuralComparer()); + (ValueConverter)new BytesToStringConverter(), new ArrayStructuralComparer()); b.Property(e => e.BytesAsNullableString).HasConversion( - (ValueConverter?)new BytesToStringConverter(), new ArrayStructuralComparer()); + (ValueConverter)new BytesToStringConverter(), new ArrayStructuralComparer()); b.Property(e => e.NullableBytesAsString).HasConversion( new BytesToStringConverter(), new ArrayStructuralComparer()); b.Property(e => e.NullableBytesAsNullableString).HasConversion( @@ -684,25 +684,25 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con b.Property(e => e.NullableGuidToBytes).HasConversion(new GuidToBytesConverter()); b.Property(e => e.NullableGuidToNullableBytes).HasConversion(new GuidToBytesConverter()); - b.Property(e => e.IPAddressToString).HasConversion((ValueConverter?)new IPAddressToStringConverter()); - b.Property(e => e.IPAddressToNullableString).HasConversion((ValueConverter?)new IPAddressToStringConverter()); + b.Property(e => e.IPAddressToString).HasConversion((ValueConverter)new IPAddressToStringConverter()); + b.Property(e => e.IPAddressToNullableString).HasConversion((ValueConverter)new IPAddressToStringConverter()); b.Property(e => e.NullableIPAddressToString).HasConversion(new IPAddressToStringConverter()); b.Property(e => e.NullableIPAddressToNullableString).HasConversion(new IPAddressToStringConverter()); - b.Property(e => e.IPAddressToBytes).HasConversion((ValueConverter?)new IPAddressToBytesConverter()); - b.Property(e => e.IPAddressToNullableBytes).HasConversion((ValueConverter?)new IPAddressToBytesConverter()); + b.Property(e => e.IPAddressToBytes).HasConversion((ValueConverter)new IPAddressToBytesConverter()); + b.Property(e => e.IPAddressToNullableBytes).HasConversion((ValueConverter)new IPAddressToBytesConverter()); b.Property(e => e.NullableIPAddressToBytes).HasConversion(new IPAddressToBytesConverter()); b.Property(e => e.NullableIPAddressToNullableBytes).HasConversion(new IPAddressToBytesConverter()); - b.Property(e => e.PhysicalAddressToString).HasConversion((ValueConverter?)new PhysicalAddressToStringConverter()); + b.Property(e => e.PhysicalAddressToString).HasConversion((ValueConverter)new PhysicalAddressToStringConverter()); b.Property(e => e.PhysicalAddressToNullableString) - .HasConversion((ValueConverter?)new PhysicalAddressToStringConverter()); + .HasConversion((ValueConverter)new PhysicalAddressToStringConverter()); b.Property(e => e.NullablePhysicalAddressToString).HasConversion(new PhysicalAddressToStringConverter()); b.Property(e => e.NullablePhysicalAddressToNullableString).HasConversion(new PhysicalAddressToStringConverter()); - b.Property(e => e.PhysicalAddressToBytes).HasConversion((ValueConverter?)new PhysicalAddressToBytesConverter()); + b.Property(e => e.PhysicalAddressToBytes).HasConversion((ValueConverter)new PhysicalAddressToBytesConverter()); b.Property(e => e.PhysicalAddressToNullableBytes) - .HasConversion((ValueConverter?)new PhysicalAddressToBytesConverter()); + .HasConversion((ValueConverter)new PhysicalAddressToBytesConverter()); b.Property(e => e.NullablePhysicalAddressToBytes).HasConversion(new PhysicalAddressToBytesConverter()); b.Property(e => e.NullablePhysicalAddressToNullableBytes).HasConversion(new PhysicalAddressToBytesConverter()); @@ -718,52 +718,52 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con b.Property(e => e.StringToBool).HasConversion(new StringToBoolConverter()); b.Property(e => e.StringToNullableBool).HasConversion(new StringToBoolConverter()); - b.Property(e => e.NullableStringToBool).HasConversion((ValueConverter?)new StringToBoolConverter()); - b.Property(e => e.NullableStringToNullableBool).HasConversion((ValueConverter?)new StringToBoolConverter()); + b.Property(e => e.NullableStringToBool).HasConversion((ValueConverter)new StringToBoolConverter()); + b.Property(e => e.NullableStringToNullableBool).HasConversion((ValueConverter)new StringToBoolConverter()); - b.Property(e => e.StringToBytes).HasConversion((ValueConverter?)new StringToBytesConverter(Encoding.UTF32)); - b.Property(e => e.StringToNullableBytes).HasConversion((ValueConverter?)new StringToBytesConverter(Encoding.UTF32)); + b.Property(e => e.StringToBytes).HasConversion((ValueConverter)new StringToBytesConverter(Encoding.UTF32)); + b.Property(e => e.StringToNullableBytes).HasConversion((ValueConverter)new StringToBytesConverter(Encoding.UTF32)); b.Property(e => e.NullableStringToBytes).HasConversion(new StringToBytesConverter(Encoding.UTF32)); b.Property(e => e.NullableStringToNullableBytes).HasConversion(new StringToBytesConverter(Encoding.UTF32)); b.Property(e => e.StringToChar).HasConversion(new StringToCharConverter()); b.Property(e => e.StringToNullableChar).HasConversion(new StringToCharConverter()); - b.Property(e => e.NullableStringToChar).HasConversion((ValueConverter?)new StringToCharConverter()); - b.Property(e => e.NullableStringToNullableChar).HasConversion((ValueConverter?)new StringToCharConverter()); + b.Property(e => e.NullableStringToChar).HasConversion((ValueConverter)new StringToCharConverter()); + b.Property(e => e.NullableStringToNullableChar).HasConversion((ValueConverter)new StringToCharConverter()); b.Property(e => e.StringToDateTime).HasConversion(new StringToDateTimeConverter()); b.Property(e => e.StringToNullableDateTime).HasConversion(new StringToDateTimeConverter()); - b.Property(e => e.NullableStringToDateTime).HasConversion((ValueConverter?)new StringToDateTimeConverter()); - b.Property(e => e.NullableStringToNullableDateTime).HasConversion((ValueConverter?)new StringToDateTimeConverter()); + b.Property(e => e.NullableStringToDateTime).HasConversion((ValueConverter)new StringToDateTimeConverter()); + b.Property(e => e.NullableStringToNullableDateTime).HasConversion((ValueConverter)new StringToDateTimeConverter()); b.Property(e => e.StringToDateTimeOffset).HasConversion(new StringToDateTimeOffsetConverter()); b.Property(e => e.StringToNullableDateTimeOffset).HasConversion(new StringToDateTimeOffsetConverter()); b.Property(e => e.NullableStringToDateTimeOffset) - .HasConversion((ValueConverter?)new StringToDateTimeOffsetConverter()); + .HasConversion((ValueConverter)new StringToDateTimeOffsetConverter()); b.Property(e => e.NullableStringToNullableDateTimeOffset) - .HasConversion((ValueConverter?)new StringToDateTimeOffsetConverter()); + .HasConversion((ValueConverter)new StringToDateTimeOffsetConverter()); b.Property(e => e.StringToEnum).HasConversion(new StringToEnumConverter()); b.Property(e => e.StringToNullableEnum).HasConversion(new StringToEnumConverter()); - b.Property(e => e.NullableStringToEnum).HasConversion((ValueConverter?)new StringToEnumConverter()); + b.Property(e => e.NullableStringToEnum).HasConversion((ValueConverter)new StringToEnumConverter()); b.Property(e => e.NullableStringToNullableEnum) - .HasConversion((ValueConverter?)new StringToEnumConverter()); + .HasConversion((ValueConverter)new StringToEnumConverter()); b.Property(e => e.StringToGuid).HasConversion(new StringToGuidConverter()); b.Property(e => e.StringToNullableGuid).HasConversion(new StringToGuidConverter()); - b.Property(e => e.NullableStringToGuid).HasConversion((ValueConverter?)new StringToGuidConverter()); - b.Property(e => e.NullableStringToNullableGuid).HasConversion((ValueConverter?)new StringToGuidConverter()); + b.Property(e => e.NullableStringToGuid).HasConversion((ValueConverter)new StringToGuidConverter()); + b.Property(e => e.NullableStringToNullableGuid).HasConversion((ValueConverter)new StringToGuidConverter()); b.Property(e => e.StringToNumber).HasConversion(new StringToNumberConverter()); b.Property(e => e.StringToNullableNumber).HasConversion(new StringToNumberConverter()); - b.Property(e => e.NullableStringToNumber).HasConversion((ValueConverter?)new StringToNumberConverter()); + b.Property(e => e.NullableStringToNumber).HasConversion((ValueConverter)new StringToNumberConverter()); b.Property(e => e.NullableStringToNullableNumber) - .HasConversion((ValueConverter?)new StringToNumberConverter()); + .HasConversion((ValueConverter)new StringToNumberConverter()); b.Property(e => e.StringToTimeSpan).HasConversion(new StringToTimeSpanConverter()); b.Property(e => e.StringToNullableTimeSpan).HasConversion(new StringToTimeSpanConverter()); - b.Property(e => e.NullableStringToTimeSpan).HasConversion((ValueConverter?)new StringToTimeSpanConverter()); - b.Property(e => e.NullableStringToNullableTimeSpan).HasConversion((ValueConverter?)new StringToTimeSpanConverter()); + b.Property(e => e.NullableStringToTimeSpan).HasConversion((ValueConverter)new StringToTimeSpanConverter()); + b.Property(e => e.NullableStringToNullableTimeSpan).HasConversion((ValueConverter)new StringToTimeSpanConverter()); b.Property(e => e.TimeSpanToTicks).HasConversion(new TimeSpanToTicksConverter()); b.Property(e => e.TimeSpanToNullableTicks).HasConversion(new TimeSpanToTicksConverter()); @@ -775,8 +775,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con b.Property(e => e.NullableTimeSpanToString).HasConversion(new TimeSpanToStringConverter()); b.Property(e => e.NullableTimeSpanToNullableString).HasConversion(new TimeSpanToStringConverter()); - b.Property(e => e.UriToString).HasConversion((ValueConverter?)new UriToStringConverter()); - b.Property(e => e.UriToNullableString).HasConversion((ValueConverter?)new UriToStringConverter()); + b.Property(e => e.UriToString).HasConversion((ValueConverter)new UriToStringConverter()); + b.Property(e => e.UriToNullableString).HasConversion((ValueConverter)new UriToStringConverter()); b.Property(e => e.NullableUriToString).HasConversion(new UriToStringConverter()); b.Property(e => e.NullableUriToNullableString).HasConversion(new UriToStringConverter()); diff --git a/test/EFCore.SqlServer.Tests/Infrastructure/SqlServerModelValidatorTest.cs b/test/EFCore.SqlServer.Tests/Infrastructure/SqlServerModelValidatorTest.cs index 88a0189e171..e1a3a735149 100644 --- a/test/EFCore.SqlServer.Tests/Infrastructure/SqlServerModelValidatorTest.cs +++ b/test/EFCore.SqlServer.Tests/Infrastructure/SqlServerModelValidatorTest.cs @@ -27,7 +27,7 @@ public override void Detects_duplicate_column_names() RelationalStrings.DuplicateColumnNameDataTypeMismatch( nameof(Animal), nameof(Animal.Id), nameof(Animal), nameof(Animal.Name), "Name", nameof(Animal), "int", "nvarchar(max)"), - modelBuilder.Model); + modelBuilder); } public override void Detects_incompatible_shared_columns_with_shared_table() @@ -42,7 +42,7 @@ public override void Detects_incompatible_shared_columns_with_shared_table() VerifyError( RelationalStrings.DuplicateColumnNameDataTypeMismatch( - nameof(A), nameof(A.P0), nameof(B), nameof(B.P0), nameof(B.P0), "Table", "someInt", "int"), modelBuilder.Model); + nameof(A), nameof(A.P0), nameof(B), nameof(B.P0), nameof(B.P0), "Table", "someInt", "int"), modelBuilder); } public override void Detects_duplicate_columns_in_derived_types_with_different_types() @@ -56,7 +56,20 @@ public override void Detects_duplicate_columns_in_derived_types_with_different_t VerifyError( RelationalStrings.DuplicateColumnNameDataTypeMismatch( nameof(Cat), nameof(Cat.Type), nameof(Dog), nameof(Dog.Type), nameof(Cat.Type), nameof(Animal), "nvarchar(max)", - "int"), modelBuilder.Model); + "int"), modelBuilder); + } + + public override void Passes_for_ForeignKey_on_inherited_generated_composite_key_property() + { + var modelBuilder = CreateConventionalModelBuilder(); + modelBuilder.Entity().Property("SomeId").ValueGeneratedOnAdd(); + modelBuilder.Entity().Property("SomeOtherId").ValueGeneratedOnAdd() + .Metadata.SetValueGenerationStrategy(SqlServerValueGenerationStrategy.None); + modelBuilder.Entity().HasAlternateKey("SomeId", "SomeOtherId"); + modelBuilder.Entity>().HasOne().WithOne().HasForeignKey>("SomeId"); + modelBuilder.Entity>(); + + Validate(modelBuilder); } [ConditionalFact] @@ -75,7 +88,7 @@ public virtual void Passes_for_duplicate_column_names_within_hierarchy_with_iden db.Property(d => d.Identity).UseIdentityColumn(2, 3).HasColumnName(nameof(Dog.Identity)); }); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalFact] @@ -97,7 +110,7 @@ public virtual void Detects_duplicate_column_names_within_hierarchy_with_differe VerifyError( SqlServerStrings.DuplicateColumnIdentitySeedMismatch( nameof(Cat), nameof(Cat.Identity), nameof(Dog), nameof(Dog.Identity), nameof(Cat.Identity), nameof(Animal)), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -119,7 +132,7 @@ public virtual void Detects_duplicate_column_names_within_hierarchy_with_differe VerifyError( SqlServerStrings.DuplicateColumnIdentityIncrementMismatch( nameof(Cat), nameof(Cat.Identity), nameof(Dog), nameof(Dog.Identity), nameof(Cat.Identity), nameof(Animal)), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -130,7 +143,7 @@ public virtual void Passes_for_identity_seed_and_increment_on_owner() modelBuilder.Entity().OwnsOne(a => a.FavoritePerson); modelBuilder.Entity(); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalFact] @@ -151,7 +164,7 @@ public virtual void Passes_for_duplicate_column_names_with_HiLoSequence() db.HasOne().WithOne().HasForeignKey(d => d.Id); }); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalFact] @@ -175,7 +188,7 @@ public virtual void Detects_duplicate_column_names_with_different_HiLoSequence_n VerifyError( SqlServerStrings.DuplicateColumnSequenceMismatch( nameof(Cat), nameof(Cat.Id), nameof(Dog), nameof(Dog.Id), nameof(Cat.Id), nameof(Animal)), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -199,7 +212,7 @@ public virtual void Detects_duplicate_column_name_with_different_HiLoSequence_sc VerifyError( SqlServerStrings.DuplicateColumnSequenceMismatch( nameof(Cat), nameof(Cat.Id), nameof(Dog), nameof(Dog.Id), nameof(Cat.Id), nameof(Animal)), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -222,7 +235,7 @@ public virtual void Detects_duplicate_column_names_within_hierarchy_with_differe VerifyError( SqlServerStrings.DuplicateColumnNameValueGenerationStrategyMismatch( nameof(Cat), nameof(Cat.Identity), nameof(Dog), nameof(Dog.Identity), nameof(Cat.Identity), nameof(Animal)), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -246,7 +259,7 @@ public virtual void Detects_duplicate_column_names_within_hierarchy_with_differe VerifyError( SqlServerStrings.DuplicateColumnSparsenessMismatch( nameof(Cat), nameof(Cat.Breed), nameof(Dog), nameof(Dog.Breed), nameof(Cat.Breed), nameof(Animal)), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -259,7 +272,7 @@ public virtual void Passes_for_incompatible_foreignKeys_within_hierarchy_when_on var fk2 = modelBuilder.Entity().HasOne().WithMany().HasForeignKey(d => d.Name).HasPrincipalKey(p => p.Name) .OnDelete(DeleteBehavior.SetNull).Metadata; - Validate(modelBuilder.Model); + Validate(modelBuilder); Assert.Equal("FK_Animal_Person_Name", fk1.GetConstraintName()); Assert.Equal("FK_Animal_Person_Name1", fk2.GetConstraintName()); @@ -275,7 +288,7 @@ public virtual void Passes_for_compatible_duplicate_convention_indexes_for_forei modelBuilder.Entity().HasOne().WithMany().HasForeignKey(d => d.Name).HasPrincipalKey(p => p.Name) .HasConstraintName("FK_Animal_Person_Name"); - var model = Validate(modelBuilder.Model); + var model = Validate(modelBuilder); Assert.Equal("IX_Animal_Name", model.FindEntityType(typeof(Cat)).GetDeclaredIndexes().Single().GetDatabaseName()); Assert.Equal("IX_Animal_Name", model.FindEntityType(typeof(Dog)).GetDeclaredIndexes().Single().GetDatabaseName()); @@ -294,7 +307,7 @@ public virtual void Detects_duplicate_index_names_within_hierarchy_differently_c "{'" + nameof(Dog.Name) + "'}", nameof(Dog), "{'" + nameof(Cat.Name) + "'}", nameof(Cat), nameof(Animal), "IX_Animal_Name"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -310,7 +323,7 @@ public virtual void Detects_duplicate_index_names_within_hierarchy_different_fil "{'" + nameof(Dog.Name) + "'}", nameof(Dog), "{'" + nameof(Cat.Name) + "'}", nameof(Cat), nameof(Animal), "IX_Animal_Name"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -326,7 +339,7 @@ public virtual void Detects_duplicate_index_names_within_hierarchy_differently_o "{'" + nameof(Dog.Name) + "'}", nameof(Dog), "{'" + nameof(Cat.Name) + "'}", nameof(Cat), nameof(Animal), "IX_Animal_Name"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -343,7 +356,7 @@ public virtual void Detects_duplicate_index_names_within_hierarchy_with_differen "{'" + nameof(Cat.Name) + "'}", nameof(Cat), nameof(Animal), "IX_Animal_Name", "{'Dog_Identity'}", "{}"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -353,7 +366,7 @@ public void Detects_missing_include_properties() modelBuilder.Entity().Property(c => c.Type); modelBuilder.Entity().HasIndex(nameof(Dog.Name)).IncludeProperties(nameof(Dog.Type), "Tag"); - VerifyError(SqlServerStrings.IncludePropertyNotFound("Tag", "{'Name'}", nameof(Dog)), modelBuilder.Model); + VerifyError(SqlServerStrings.IncludePropertyNotFound("Tag", "{'Name'}", nameof(Dog)), modelBuilder); } [ConditionalFact] @@ -363,7 +376,7 @@ public void Detects_duplicate_include_properties() modelBuilder.Entity().Property(c => c.Type); modelBuilder.Entity().HasIndex(nameof(Dog.Name)).IncludeProperties(nameof(Dog.Type), nameof(Dog.Type)); - VerifyError(SqlServerStrings.IncludePropertyDuplicated(nameof(Dog), nameof(Dog.Type), "{'Name'}"), modelBuilder.Model); + VerifyError(SqlServerStrings.IncludePropertyDuplicated(nameof(Dog), nameof(Dog.Type), "{'Name'}"), modelBuilder); } [ConditionalFact] @@ -373,7 +386,7 @@ public void Detects_indexed_include_properties() modelBuilder.Entity().Property(c => c.Type); modelBuilder.Entity().HasIndex(nameof(Dog.Name)).IncludeProperties(nameof(Dog.Name)); - VerifyError(SqlServerStrings.IncludePropertyInIndex(nameof(Dog), nameof(Dog.Name), "{'Name'}"), modelBuilder.Model); + VerifyError(SqlServerStrings.IncludePropertyInIndex(nameof(Dog), nameof(Dog.Name), "{'Name'}"), modelBuilder); } [ConditionalFact] @@ -389,7 +402,7 @@ public virtual void Detects_incompatible_memory_optimized_shared_table() VerifyError( SqlServerStrings.IncompatibleTableMemoryOptimizedMismatch("Table", nameof(A), nameof(B), nameof(A), nameof(B)), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -406,7 +419,7 @@ public virtual void Detects_incompatible_non_clustered_shared_key() VerifyError( SqlServerStrings.DuplicateKeyMismatchedClustering("{'Id'}", nameof(B), "{'Id'}", nameof(A), "Table", "PK_Table"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -419,7 +432,7 @@ public virtual void Detects_decimal_keys() VerifyWarning( SqlServerResources.LogDecimalTypeKey(new TestLogger()) - .GenerateMessage("Price", nameof(Animal)), modelBuilder.Model); + .GenerateMessage("Price", nameof(Animal)), modelBuilder); } [ConditionalFact] @@ -430,7 +443,7 @@ public virtual void Detects_default_decimal_mapping() VerifyWarning( SqlServerResources.LogDefaultDecimalTypeColumn(new TestLogger()) - .GenerateMessage("Price", nameof(Animal)), modelBuilder.Model); + .GenerateMessage("Price", nameof(Animal)), modelBuilder); } [ConditionalFact] @@ -441,7 +454,7 @@ public virtual void Detects_default_nullable_decimal_mapping() VerifyWarning( SqlServerResources.LogDefaultDecimalTypeColumn(new TestLogger()) - .GenerateMessage("Price", nameof(Animal)), modelBuilder.Model); + .GenerateMessage("Price", nameof(Animal)), modelBuilder); } [ConditionalFact] @@ -453,7 +466,7 @@ public virtual void Does_not_warn_if_decimal_column_has_precision_and_scale() VerifyLogDoesNotContain( SqlServerResources.LogDefaultDecimalTypeColumn(new TestLogger()) - .GenerateMessage("Price", nameof(Animal)), modelBuilder.Model); + .GenerateMessage("Price", nameof(Animal)), modelBuilder); } [ConditionalFact] @@ -466,7 +479,7 @@ public virtual void Does_not_warn_if_default_decimal_mapping_has_non_decimal_to_ VerifyLogDoesNotContain( SqlServerResources.LogDefaultDecimalTypeColumn(new TestLogger()) - .GenerateMessage("Price", nameof(Animal)), modelBuilder.Model); + .GenerateMessage("Price", nameof(Animal)), modelBuilder); } [ConditionalFact] @@ -479,7 +492,7 @@ public virtual void Warn_if_default_decimal_mapping_has_decimal_to_decimal_value VerifyWarning( SqlServerResources.LogDefaultDecimalTypeColumn(new TestLogger()) - .GenerateMessage("Price", nameof(Animal)), modelBuilder.Model); + .GenerateMessage("Price", nameof(Animal)), modelBuilder); } [ConditionalFact] @@ -491,7 +504,7 @@ public void Detects_byte_identity_column() VerifyWarning( SqlServerResources.LogByteIdentityColumn(new TestLogger()) - .GenerateMessage("Bite", nameof(Dog)), modelBuilder.Model); + .GenerateMessage("Bite", nameof(Dog)), modelBuilder); } [ConditionalFact] @@ -503,7 +516,7 @@ public void Detects_nullable_byte_identity_column() VerifyWarning( SqlServerResources.LogByteIdentityColumn(new TestLogger()) - .GenerateMessage("Bite", nameof(Dog)), modelBuilder.Model); + .GenerateMessage("Bite", nameof(Dog)), modelBuilder); } [ConditionalFact] @@ -515,7 +528,7 @@ public void Detects_multiple_identity_properties() modelBuilder.Entity().Property(c => c.Type).UseIdentityColumn(); modelBuilder.Entity().Property("Tag").UseIdentityColumn(); - VerifyError(SqlServerStrings.MultipleIdentityColumns("'Dog.Tag', 'Dog.Type'", nameof(Dog)), modelBuilder.Model); + VerifyError(SqlServerStrings.MultipleIdentityColumns("'Dog.Tag', 'Dog.Type'", nameof(Dog)), modelBuilder); } [ConditionalFact] @@ -525,7 +538,7 @@ public void Passes_for_non_key_identity() modelBuilder.Entity().Property(d => d.Id).ValueGeneratedNever(); modelBuilder.Entity().Property(c => c.Type).UseIdentityColumn(); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalFact] @@ -538,7 +551,7 @@ public void Passes_for_non_key_identity_on_model() modelBuilder.Entity().Property(c => c.Id).ValueGeneratedNever(); modelBuilder.Entity().Property(c => c.Type).ValueGeneratedOnAdd(); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalFact] @@ -547,7 +560,7 @@ public void Detects_non_key_SequenceHiLo() var modelBuilder = CreateConventionalModelBuilder(); modelBuilder.Entity().Property(c => c.Type).UseHiLo(); - VerifyError(SqlServerStrings.NonKeyValueGeneration(nameof(Dog.Type), nameof(Dog)), modelBuilder.Model); + VerifyError(SqlServerStrings.NonKeyValueGeneration(nameof(Dog.Type), nameof(Dog)), modelBuilder); } [ConditionalFact] @@ -559,7 +572,7 @@ public void Passes_for_non_key_SequenceHiLo_on_model() modelBuilder.Entity().Property(c => c.Type).ValueGeneratedOnAdd(); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalTheory] @@ -577,7 +590,7 @@ public void Metadata_throws_when_setting_conflicting_serverGenerated_values(stri VerifyError( RelationalStrings.ConflictingColumnServerGeneration(firstConfiguration, "NullableInt", secondConfiguration), - modelBuilder.Model); + modelBuilder); } [ConditionalTheory] @@ -599,7 +612,7 @@ public void Metadata_throws_when_setting_conflicting_serverGenerated_values(stri VerifyWarning( SqlServerResources.LogConflictingValueGenerationStrategies(new TestLogger()) .GenerateMessage(sqlServerValueGenerationStrategy.ToString(), conflictingValueGenerationStrategy, "Id", nameof(Dog)), - modelBuilder.Model); + modelBuilder); } [ConditionalTheory] @@ -623,7 +636,7 @@ public void Metadata_throws_when_setting_conflicting_serverGenerated_values(stri RelationalResources.LogKeyHasDefaultValue(new TestLogger()) .GenerateMessage("Id", nameof(Dog)) }, - modelBuilder.Model); + modelBuilder); } protected virtual void ConfigureProperty(IMutableProperty property, string configuration, string value) diff --git a/test/EFCore.SqlServer.Tests/Migrations/SqlServerMigrationsAnnotationProviderTest.cs b/test/EFCore.SqlServer.Tests/Migrations/SqlServerMigrationsAnnotationProviderTest.cs index b68b0faa6a4..316b1ef7d99 100644 --- a/test/EFCore.SqlServer.Tests/Migrations/SqlServerMigrationsAnnotationProviderTest.cs +++ b/test/EFCore.SqlServer.Tests/Migrations/SqlServerMigrationsAnnotationProviderTest.cs @@ -24,7 +24,7 @@ public void For_property_handles_identity_annotations() var modelBuilder = SqlServerTestHelpers.Instance.CreateConventionBuilder(); modelBuilder.Entity().Property("Id").UseIdentityColumn(2, 3); - var model = SqlServerTestHelpers.Instance.Finalize(modelBuilder, designTime: true); + var model = modelBuilder.FinalizeModel(designTime: true); var property = model.FindEntityType(typeof(Entity)).FindProperty("Id"); var migrationAnnotations = _annotations.For(property.GetTableColumnMappings().Single().Column, true).ToList(); @@ -39,7 +39,7 @@ public void Resolves_column_names_for_Index_with_included_properties() var modelBuilder = SqlServerTestHelpers.Instance.CreateConventionBuilder(); modelBuilder.Entity().Property(e => e.IncludedProp).HasColumnName("IncludedColumn"); modelBuilder.Entity().HasIndex(e => e.IndexedProp).IncludeProperties(e => e.IncludedProp); - var model = SqlServerTestHelpers.Instance.Finalize(modelBuilder, designTime: true); + var model = modelBuilder.FinalizeModel(designTime: true); Assert.Contains( _annotations.For(model.FindEntityType(typeof(Entity)).GetIndexes().Single().GetMappedTableIndexes().Single(), true), diff --git a/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderGenericTest.cs b/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderGenericTest.cs index 0ae9dcf31ed..79325022bd7 100644 --- a/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderGenericTest.cs +++ b/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderGenericTest.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Collections.Generic; using System.Linq; using Microsoft.EntityFrameworkCore.Metadata; @@ -73,8 +74,8 @@ public virtual void Index_has_a_filter_if_nonclustered_unique_with_nullable_prop Assert.Null(index.GetFilter()); } - protected override TestModelBuilder CreateModelBuilder() - => CreateTestModelBuilder(SqlServerTestHelpers.Instance); + protected override TestModelBuilder CreateModelBuilder(Action configure = null) + => CreateTestModelBuilder(SqlServerTestHelpers.Instance, configure); } public class SqlServerGenericInheritance : GenericInheritance @@ -258,26 +259,26 @@ public class DisjointChildSubclass2 : Child { } - protected override TestModelBuilder CreateModelBuilder() - => CreateTestModelBuilder(SqlServerTestHelpers.Instance); + protected override TestModelBuilder CreateModelBuilder(Action configure = null) + => CreateTestModelBuilder(SqlServerTestHelpers.Instance, configure); } public class SqlServerGenericOneToMany : GenericOneToMany { - protected override TestModelBuilder CreateModelBuilder() - => CreateTestModelBuilder(SqlServerTestHelpers.Instance); + protected override TestModelBuilder CreateModelBuilder(Action configure = null) + => CreateTestModelBuilder(SqlServerTestHelpers.Instance, configure); } public class SqlServerGenericManyToOne : GenericManyToOne { - protected override TestModelBuilder CreateModelBuilder() - => CreateTestModelBuilder(SqlServerTestHelpers.Instance); + protected override TestModelBuilder CreateModelBuilder(Action configure = null) + => CreateTestModelBuilder(SqlServerTestHelpers.Instance, configure); } public class SqlServerGenericOneToOne : GenericOneToOne { - protected override TestModelBuilder CreateModelBuilder() - => CreateTestModelBuilder(SqlServerTestHelpers.Instance); + protected override TestModelBuilder CreateModelBuilder(Action configure = null) + => CreateTestModelBuilder(SqlServerTestHelpers.Instance, configure); } public class SqlServerGenericManyToMany : GenericManyToMany @@ -338,8 +339,8 @@ public virtual void Join_entity_type_uses_default_schema_if_related_are_differen Assert.Equal(2, productCategoryType.GetForeignKeys().Count()); } - protected override TestModelBuilder CreateModelBuilder() - => CreateTestModelBuilder(SqlServerTestHelpers.Instance); + protected override TestModelBuilder CreateModelBuilder(Action configure = null) + => CreateTestModelBuilder(SqlServerTestHelpers.Instance, configure); } public class SqlServerGenericOwnedTypes : GenericOwnedTypes @@ -699,8 +700,8 @@ public override void Can_configure_owned_type_key() Assert.Equal(nameof(CustomerDetails.Id), owned.FindPrimaryKey().Properties.Single().Name); } - protected override TestModelBuilder CreateModelBuilder() - => CreateTestModelBuilder(SqlServerTestHelpers.Instance); + protected override TestModelBuilder CreateModelBuilder(Action configure = null) + => CreateTestModelBuilder(SqlServerTestHelpers.Instance, configure); } } } diff --git a/test/EFCore.Sqlite.Tests/Infrastructure/SqliteModelValidatorTest.cs b/test/EFCore.Sqlite.Tests/Infrastructure/SqliteModelValidatorTest.cs index 4ba630228ac..1a69a0dd15e 100644 --- a/test/EFCore.Sqlite.Tests/Infrastructure/SqliteModelValidatorTest.cs +++ b/test/EFCore.Sqlite.Tests/Infrastructure/SqliteModelValidatorTest.cs @@ -23,7 +23,7 @@ public override void Detects_duplicate_column_names() RelationalStrings.DuplicateColumnNameDataTypeMismatch( nameof(Animal), nameof(Animal.Id), nameof(Animal), nameof(Animal.Name), "Name", nameof(Animal), "INTEGER", "TEXT"), - modelBuilder.Model); + modelBuilder); } public override void Detects_duplicate_columns_in_derived_types_with_different_types() @@ -36,7 +36,7 @@ public override void Detects_duplicate_columns_in_derived_types_with_different_t VerifyError( RelationalStrings.DuplicateColumnNameDataTypeMismatch( - typeof(Cat).Name, "Type", typeof(Dog).Name, "Type", "Type", nameof(Animal), "TEXT", "INTEGER"), modelBuilder.Model); + typeof(Cat).Name, "Type", typeof(Dog).Name, "Type", "Type", nameof(Animal), "TEXT", "INTEGER"), modelBuilder); } [ConditionalFact] @@ -50,7 +50,7 @@ public virtual void Detects_duplicate_column_names_within_hierarchy_with_differe VerifyError( SqliteStrings.DuplicateColumnNameSridMismatch( - nameof(Cat), nameof(Cat.Breed), nameof(Dog), nameof(Dog.Breed), nameof(Cat.Breed), nameof(Animal)), modelBuilder.Model); + nameof(Cat), nameof(Cat.Breed), nameof(Dog), nameof(Dog.Breed), nameof(Cat.Breed), nameof(Animal)), modelBuilder); } public override void Detects_incompatible_shared_columns_with_shared_table() @@ -68,7 +68,7 @@ public override void Detects_incompatible_shared_columns_with_shared_table() VerifyError( RelationalStrings.DuplicateColumnNameDataTypeMismatch( - nameof(A), nameof(A.P0), nameof(B), nameof(B.P0), nameof(B.P0), "Table", "someInt", "INTEGER"), modelBuilder.Model); + nameof(A), nameof(A.P0), nameof(B), nameof(B.P0), nameof(B.P0), "Table", "someInt", "INTEGER"), modelBuilder); } [ConditionalFact] @@ -79,7 +79,7 @@ public void Detects_schemas() VerifyWarning( SqliteResources.LogSchemaConfigured(new TestLogger()).GenerateMessage("Animal", "pet"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -90,7 +90,7 @@ public void Detects_sequences() VerifyWarning( SqliteResources.LogSequenceConfigured(new TestLogger()).GenerateMessage("Fibonacci"), - modelBuilder.Model); + modelBuilder); } protected override TestHelpers TestHelpers diff --git a/test/EFCore.Sqlite.Tests/Migrations/SqliteMigrationAnnotationProviderTest.cs b/test/EFCore.Sqlite.Tests/Migrations/SqliteMigrationAnnotationProviderTest.cs index 05fade2f3ce..af82c7483d1 100644 --- a/test/EFCore.Sqlite.Tests/Migrations/SqliteMigrationAnnotationProviderTest.cs +++ b/test/EFCore.Sqlite.Tests/Migrations/SqliteMigrationAnnotationProviderTest.cs @@ -12,7 +12,7 @@ namespace Microsoft.EntityFrameworkCore.Migrations { public class SqliteMigrationAnnotationProviderTest { - private readonly ModelBuilder _modelBuilder = SqliteTestHelpers.Instance.CreateConventionBuilder(); + private readonly TestHelpers.TestModelBuilder _modelBuilder = SqliteTestHelpers.Instance.CreateConventionBuilder(); private readonly SqliteAnnotationProvider _provider = new SqliteAnnotationProvider(new RelationalAnnotationProviderDependencies()); private readonly Annotation _autoincrement = new(SqliteAnnotationNames.Autoincrement, true); @@ -95,7 +95,7 @@ public void Does_not_add_Autoincrement_for_non_integer_OnAdd_property() } private IModel FinalizeModel() - => SqliteTestHelpers.Instance.Finalize(_modelBuilder); + => _modelBuilder.FinalizeModel(); private class Entity { diff --git a/test/EFCore.Tests/Infrastructure/ModelValidatorTest.PropertyMapping.cs b/test/EFCore.Tests/Infrastructure/ModelValidatorTest.PropertyMapping.cs new file mode 100644 index 00000000000..11aff80b3e8 --- /dev/null +++ b/test/EFCore.Tests/Infrastructure/ModelValidatorTest.PropertyMapping.cs @@ -0,0 +1,258 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Threading; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Metadata.Internal; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; + +// ReSharper disable InconsistentNaming +namespace Microsoft.EntityFrameworkCore.Infrastructure +{ + public partial class ModelValidatorTest + { + [ConditionalFact] + public virtual void Throws_when_added_property_is_not_of_primitive_type() + { + var modelBuilder = CreateConventionlessModelBuilder(); + var entityTypeBuilder = modelBuilder.Entity(typeof(NonPrimitiveAsPropertyEntity)); + entityTypeBuilder.Property( + typeof(NavigationAsProperty), nameof(NonPrimitiveAsPropertyEntity.Property)); + + Assert.Equal( + CoreStrings.PropertyNotMapped( + typeof(NonPrimitiveAsPropertyEntity).ShortDisplayName(), + nameof(NonPrimitiveAsPropertyEntity.Property), + typeof(NavigationAsProperty).ShortDisplayName()), + Assert.Throws(() => Validate(modelBuilder)).Message); + } + + [ConditionalFact] + public virtual void Does_not_throw_when_added_shadow_property_by_convention_is_not_of_primitive_type() + { + var modelBuilder = CreateConventionlessModelBuilder(); + var entityTypeBuilder = modelBuilder.Entity(typeof(NonPrimitiveAsPropertyEntity)).HasNoKey(); + entityTypeBuilder.GetInfrastructure().Property(typeof(NavigationAsProperty), "ShadowProperty"); + entityTypeBuilder.Ignore(nameof(NonPrimitiveAsPropertyEntity.Property)); + + Validate(modelBuilder); + } + + [ConditionalFact] + public virtual void Throws_when_primitive_type_property_is_not_added_or_ignored() + { + var modelBuilder = CreateConventionlessModelBuilder(); + modelBuilder.Entity(typeof(PrimitivePropertyEntity)); + + Assert.Equal( + CoreStrings.PropertyNotAdded( + typeof(PrimitivePropertyEntity).ShortDisplayName(), "Property", typeof(int).DisplayName()), + Assert.Throws(() => Validate(modelBuilder)).Message); + } + + [ConditionalFact] + public virtual void Throws_when_nonprimitive_value_type_property_is_not_added_or_ignored() + { + var modelBuilder = CreateConventionlessModelBuilder(); + modelBuilder.Entity(typeof(NonPrimitiveValueTypePropertyEntity)); + + Assert.Equal( + CoreStrings.PropertyNotAdded( + typeof(NonPrimitiveValueTypePropertyEntity).ShortDisplayName(), "Property", typeof(CancellationToken).Name), + Assert.Throws(() => Validate(modelBuilder)).Message); + } + + [ConditionalFact] + public virtual void Throws_when_keyless_type_property_is_not_added_or_ignored() + { + var modelBuilder = CreateConventionlessModelBuilder(); + modelBuilder.Entity(typeof(NonPrimitiveReferenceTypePropertyEntity)); + + Assert.Equal( + CoreStrings.PropertyNotAdded( + typeof(NonPrimitiveReferenceTypePropertyEntity).ShortDisplayName(), + nameof(NonPrimitiveReferenceTypePropertyEntity.Property), + typeof(ICollection).ShortDisplayName()), + Assert.Throws(() => Validate(modelBuilder)).Message); + } + + [ConditionalFact] + public virtual void Does_not_throw_when_primitive_type_property_is_added() + { + var modelBuilder = CreateConventionlessModelBuilder(); + var entityTypeBuilder = modelBuilder.Entity(typeof(PrimitivePropertyEntity)).HasNoKey(); + entityTypeBuilder.Property(typeof(int), "Property"); + + Validate(modelBuilder); + } + + [ConditionalFact] + public virtual void Does_not_throw_when_primitive_type_property_is_ignored() + { + var modelBuilder = CreateConventionlessModelBuilder(); + var entityTypeBuilder = modelBuilder.Entity(typeof(PrimitivePropertyEntity)).HasNoKey(); + entityTypeBuilder.Ignore("Property"); + + Validate(modelBuilder); + } + + [ConditionalFact] + public virtual void Throws_when_navigation_is_not_added_or_ignored() + { + var modelBuilder = CreateConventionlessModelBuilder(); + modelBuilder.Entity(typeof(NavigationEntity)); + modelBuilder.Entity(typeof(PrimitivePropertyEntity)); + + Assert.Equal( + CoreStrings.NavigationNotAdded( + typeof(NavigationEntity).ShortDisplayName(), "Navigation", typeof(PrimitivePropertyEntity).Name), + Assert.Throws(() => Validate(modelBuilder)).Message); + } + + [ConditionalFact] + public virtual void Does_not_throw_when_navigation_is_added() + { + var modelBuilder = CreateConventionlessModelBuilder(); + var entityTypeBuilder = modelBuilder.Entity(typeof(NavigationEntity)); + entityTypeBuilder.Property("Id"); + entityTypeBuilder.HasKey("Id"); + var referencedEntityTypeBuilder = modelBuilder.Entity(typeof(PrimitivePropertyEntity)); + referencedEntityTypeBuilder.Ignore("Property"); + referencedEntityTypeBuilder.Property("Id"); + referencedEntityTypeBuilder.HasKey("Id"); + entityTypeBuilder.GetInfrastructure().HasRelationship( + (IConventionEntityType)referencedEntityTypeBuilder.Metadata, "Navigation", null, setTargetAsPrincipal: true); + + Validate(modelBuilder); + } + + [ConditionalFact] + public virtual void Does_not_throw_when_navigation_is_ignored() + { + var modelBuilder = CreateConventionlessModelBuilder(); + var entityTypeBuilder = modelBuilder.Entity(typeof(NavigationEntity)).HasNoKey(); + entityTypeBuilder.Ignore("Navigation"); + + Validate(modelBuilder); + } + + [ConditionalFact] + public virtual void Does_not_throw_when_navigation_target_entity_is_ignored() + { + var modelBuilder = CreateConventionlessModelBuilder(); + modelBuilder.Entity(typeof(NavigationEntity)).HasNoKey(); + modelBuilder.Ignore(typeof(PrimitivePropertyEntity)); + + Validate(modelBuilder); + } + + [ConditionalFact] + public virtual void Does_not_throw_when_explicit_navigation_is_not_added() + { + var modelBuilder = CreateConventionlessModelBuilder(); + var entityTypeBuilder = modelBuilder.Entity(typeof(ExplicitNavigationEntity)); + var referencedEntityTypeBuilder = modelBuilder.Entity(typeof(PrimitivePropertyEntity)); + referencedEntityTypeBuilder.Ignore("Property"); + entityTypeBuilder.Property("Id"); + entityTypeBuilder.HasKey("Id"); + referencedEntityTypeBuilder.Property("Id"); + referencedEntityTypeBuilder.HasKey("Id"); + entityTypeBuilder.GetInfrastructure().HasRelationship( + (IConventionEntityType)referencedEntityTypeBuilder.Metadata, "Navigation", null); + + Validate(modelBuilder); + } + + [ConditionalFact] + public virtual void Throws_when_interface_type_property_is_not_added_or_ignored() + { + var modelBuilder = CreateConventionlessModelBuilder(); + modelBuilder.Entity(typeof(InterfaceNavigationEntity)); + + Assert.Equal( + CoreStrings.InterfacePropertyNotAdded( + typeof(InterfaceNavigationEntity).ShortDisplayName(), + "Navigation", + typeof(IList).ShortDisplayName()), + Assert.Throws(() => Validate(modelBuilder)).Message); + } + + [ConditionalFact] + public virtual void Does_not_throw_when_non_candidate_property_is_not_added() + { + var modelBuilder = CreateConventionlessModelBuilder(); + modelBuilder.Entity(typeof(NonCandidatePropertyEntity)).HasNoKey(); + + Validate(modelBuilder); + } + + protected virtual IModel Validate(TestHelpers.TestModelBuilder modelBuilder) + => modelBuilder.FinalizeModel(designTime: true); + + protected class NonPrimitiveNonNavigationAsPropertyEntity + { + } + + protected class NonPrimitiveAsPropertyEntity + { + public NavigationAsProperty Property { get; set; } + } + + protected class NavigationAsProperty + { + } + + protected class PrimitivePropertyEntity + { + public int Property { get; set; } + } + + protected class NonPrimitiveValueTypePropertyEntity + { + public CancellationToken Property { get; set; } + } + + protected class NonPrimitiveReferenceTypePropertyEntity + { + public ICollection Property { get; set; } + } + + protected class NavigationEntity + { + public PrimitivePropertyEntity Navigation { get; set; } + } + + protected class NonCandidatePropertyEntity + { + public static int StaticProperty { get; set; } + + public int _writeOnlyField = 1; + + public int WriteOnlyProperty + { + set => _writeOnlyField = value; + } + } + + protected interface INavigationEntity + { + PrimitivePropertyEntity Navigation { get; set; } + } + + protected class ExplicitNavigationEntity : INavigationEntity + { + PrimitivePropertyEntity INavigationEntity.Navigation { get; set; } + + public PrimitivePropertyEntity Navigation { get; set; } + } + + protected class InterfaceNavigationEntity + { + public IList Navigation { get; set; } + } + } +} diff --git a/test/EFCore.Tests/Infrastructure/ModelValidatorTest.cs b/test/EFCore.Tests/Infrastructure/ModelValidatorTest.cs index 218a30eeadc..f8df09899c7 100644 --- a/test/EFCore.Tests/Infrastructure/ModelValidatorTest.cs +++ b/test/EFCore.Tests/Infrastructure/ModelValidatorTest.cs @@ -11,6 +11,7 @@ using Microsoft.EntityFrameworkCore.Diagnostics.Internal; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Microsoft.EntityFrameworkCore.TestUtilities; using Microsoft.Extensions.Logging; @@ -20,22 +21,25 @@ // ReSharper disable InconsistentNaming namespace Microsoft.EntityFrameworkCore.Infrastructure { - public class ModelValidatorTest : ModelValidatorTestBase + public partial class ModelValidatorTest : ModelValidatorTestBase { [ConditionalFact] public virtual void Detects_key_property_which_cannot_be_compared() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionalModelBuilder(); - var entityType = model.AddEntityType(typeof(WithNonComparableKey)); - entityType.SetPrimaryKey(entityType.AddProperty(nameof(WithNonComparableKey.Id), typeof(NotComparable))); + modelBuilder.Entity(eb => + { + eb.Property(e => e.Id); + eb.HasKey(e => e.Id); + }); VerifyError( CoreStrings.NonComparableKeyType(nameof(WithNonComparableKey), nameof(WithNonComparableKey.Id), nameof(NotComparable)), - model); + modelBuilder); } - private class WithNonComparableKey + protected class WithNonComparableKey { public NotComparable Id { get; set; } } @@ -43,73 +47,74 @@ private class WithNonComparableKey [ConditionalFact] public virtual void Detects_unique_index_property_which_cannot_be_compared() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionalModelBuilder(); - var entityType = model.AddEntityType(typeof(WithNonComparableUniqueIndex)); - entityType.SetPrimaryKey(entityType.AddProperty(nameof(WithNonComparableUniqueIndex.Id), typeof(int))); - entityType.AddIndex(entityType.AddProperty(nameof(WithNonComparableUniqueIndex.Index), typeof(NotComparable))).IsUnique = true; + modelBuilder.Entity(eb => + { + eb.HasIndex(e => e.Index).IsUnique(); + }); VerifyError( CoreStrings.NonComparableKeyType( nameof(WithNonComparableUniqueIndex), nameof(WithNonComparableUniqueIndex.Index), nameof(NotComparable)), - model); + modelBuilder); } - private class WithNonComparableUniqueIndex + protected class WithNonComparableUniqueIndex { public int Id { get; set; } public NotComparable Index { get; set; } } [ConditionalFact] - public virtual void Ignores_normal__property_which_cannot_be_compared() + public virtual void Ignores_normal_property_which_cannot_be_compared() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionalModelBuilder(); - var entityType = model.AddEntityType(typeof(WithNonComparableNormalProperty)); - entityType.SetPrimaryKey(entityType.AddProperty(nameof(WithNonComparableNormalProperty.Id), typeof(int))); - entityType.AddProperty(nameof(WithNonComparableNormalProperty.Foo), typeof(NotComparable)); + modelBuilder.Entity(eb => + { + eb.Property(e => e.Id); + eb.HasKey(e => e.Id); + eb.Property(e => e.Foo); + }); - Validate(model); + Validate(modelBuilder); } - private class WithNonComparableNormalProperty + protected class WithNonComparableNormalProperty { public int Id { get; set; } public NotComparable Foo { get; set; } } - private struct NotComparable + protected struct NotComparable { } [ConditionalFact] public virtual void Detects_custom_converter_for_collection_type_without_comparer() { - var convertedProperty = CreateConvertedCollectionProperty(); + var modelBuilder = CreateConventionalModelBuilder(); + + IMutableProperty convertedProperty = null; + modelBuilder.Entity(eb => + { + eb.Property(e => e.Id); + convertedProperty = eb.Property(e => e.SomeStrings).Metadata; + convertedProperty.SetValueConverter( + new ValueConverter( + v => string.Join(',', v), + v => v.Split(',', StringSplitOptions.None))); + }); VerifyWarning( CoreResources.LogCollectionWithoutComparer( new TestLogger()).GenerateMessage("WithCollectionConversion", "SomeStrings"), - convertedProperty.DeclaringEntityType.Model); + modelBuilder); } [ConditionalFact] public virtual void Ignores_custom_converter_for_collection_type_with_comparer() - { - var convertedProperty = CreateConvertedCollectionProperty(); - - convertedProperty.SetValueComparer( - new ValueComparer( - (v1, v2) => v1.SequenceEqual(v2), - v => v.GetHashCode())); - - Validate(convertedProperty.DeclaringEntityType.Model); - - Assert.Empty(LoggerFactory.Log.Where(l => l.Level == LogLevel.Warning)); - } - - private IMutableProperty CreateConvertedCollectionProperty() { var modelBuilder = CreateConventionalModelBuilder(); @@ -124,10 +129,17 @@ private IMutableProperty CreateConvertedCollectionProperty() v => v.Split(',', StringSplitOptions.None))); }); - return convertedProperty; + convertedProperty.SetValueComparer( + new ValueComparer( + (v1, v2) => v1.SequenceEqual(v2), + v => v.GetHashCode())); + + Validate(modelBuilder); + + Assert.Empty(LoggerFactory.Log.Where(l => l.Level == LogLevel.Warning)); } - private class WithCollectionConversion + protected class WithCollectionConversion { public int Id { get; set; } public string[] SomeStrings { get; set; } @@ -136,7 +148,8 @@ private class WithCollectionConversion [ConditionalFact] public virtual void Ignores_binary_keys_and_strings_without_custom_comparer() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; var entityType = model.AddEntityType(typeof(WithStringAndBinaryKey)); @@ -150,12 +163,12 @@ public virtual void Ignores_binary_keys_and_strings_without_custom_comparer() stringProperty.SetValueConverter( new ValueConverter(v => v, v => v)); - Validate(model); + Validate(modelBuilder); Assert.Empty(LoggerFactory.Log.Where(l => l.Level == LogLevel.Warning)); } - private class WithStringAndBinaryKey + protected class WithStringAndBinaryKey { public byte[] Id { get; set; } public string AString { get; set; } @@ -171,7 +184,7 @@ public virtual void Detects_filter_on_derived_type() entityTypeD.SetQueryFilter((Expression>)(_ => true)); VerifyError(CoreStrings.BadFilterDerivedType(entityTypeD.GetQueryFilter(), entityTypeD.DisplayName(), entityTypeA.DisplayName()), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -186,13 +199,14 @@ public virtual void Detects_filter_on_owned_type() eb.OwnedEntityType.SetQueryFilter(queryFilter); }); - VerifyError(CoreStrings.BadFilterOwnedType(queryFilter, nameof(ReferencedEntity)), modelBuilder.Model); + VerifyError(CoreStrings.BadFilterOwnedType(queryFilter, nameof(ReferencedEntity)), modelBuilder); } [ConditionalFact] public virtual void Passes_on_shadow_key_created_explicitly() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; var entityType = model.AddEntityType(typeof(A)); SetPrimaryKey(entityType); @@ -202,14 +216,15 @@ public virtual void Passes_on_shadow_key_created_explicitly() ((IConventionEntityType)entityType).AddKey(keyProperty); VerifyWarning( - CoreResources.LogShadowPropertyCreated(new TestLogger()).GenerateMessage("A", "Key"), model, + CoreResources.LogShadowPropertyCreated(new TestLogger()).GenerateMessage("A", "Key"), modelBuilder, LogLevel.Debug); } [ConditionalFact] public virtual void Passes_on_shadow_primary_key_created_by_convention_in_dependent_type() { - var model = (IConventionModel)CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = (IConventionModel)modelBuilder.Model; var entityType = model.AddEntityType(typeof(A)); AddProperties((IMutableEntityType)entityType); @@ -220,13 +235,14 @@ public virtual void Passes_on_shadow_primary_key_created_by_convention_in_depend VerifyWarning( CoreResources.LogShadowPropertyCreated(new TestLogger()) - .GenerateMessage("A", "Key"), (IMutableModel)model, LogLevel.Debug); + .GenerateMessage("A", "Key"), modelBuilder, LogLevel.Debug); } [ConditionalFact] public virtual void Detects_shadow_key_referenced_by_foreign_key_by_convention() { - var modelBuilder = CreateConventionlessInternalModelBuilder(); + var builder = CreateConventionlessModelBuilder(); + var modelBuilder = (InternalModelBuilder)builder.GetInfrastructure(); var dependentEntityBuilder = modelBuilder.Entity(typeof(SampleEntityMinimal), ConfigurationSource.Convention); dependentEntityBuilder.Property(typeof(int), "Id", ConfigurationSource.Convention); dependentEntityBuilder.Ignore(nameof(SampleEntityMinimal.ReferencedEntity), ConfigurationSource.Explicit); @@ -255,14 +271,14 @@ public virtual void Detects_shadow_key_referenced_by_foreign_key_by_convention() typeof(ReferencedEntityMinimal).Name, "{'Foo' : string}", "{'Id' : int}"), - modelBuilder.Metadata); + builder); } [ConditionalFact] public virtual void Detects_a_null_primary_key() { - var builder = CreateConventionlessModelBuilder(); - builder.Entity( + var modelBuilder = CreateConventionlessModelBuilder(); + modelBuilder.Entity( b => { b.Property(e => e.Id); @@ -272,31 +288,34 @@ public virtual void Detects_a_null_primary_key() b.Property(e => e.P3); }); - VerifyError(CoreStrings.EntityRequiresKey(nameof(A)), builder.Model); + VerifyError(CoreStrings.EntityRequiresKey(nameof(A)), modelBuilder); } [ConditionalFact] public virtual void Detects_key_property_with_value_generated_on_update() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; var entityTypeA = model.AddEntityType(typeof(A)); SetPrimaryKey(entityTypeA); AddProperties(entityTypeA); entityTypeA.FindPrimaryKey().Properties.Single().ValueGenerated = ValueGenerated.OnUpdate; - VerifyError(CoreStrings.MutableKeyProperty(nameof(A.Id)), model); + VerifyError(CoreStrings.MutableKeyProperty(nameof(A.Id)), modelBuilder); } [ConditionalFact] public virtual void Detects_key_property_with_value_generated_on_add_or_update() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; + var entityTypeA = model.AddEntityType(typeof(A)); SetPrimaryKey(entityTypeA); AddProperties(entityTypeA); entityTypeA.FindPrimaryKey().Properties.Single().ValueGenerated = ValueGenerated.OnAddOrUpdate; - VerifyError(CoreStrings.MutableKeyProperty(nameof(A.Id)), model); + VerifyError(CoreStrings.MutableKeyProperty(nameof(A.Id)), modelBuilder); } [ConditionalFact] @@ -313,7 +332,7 @@ public virtual void Detects_relationship_cycle() VerifyError( CoreStrings.IdentifyingRelationshipCycle("A -> B -> C"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -328,7 +347,7 @@ public virtual void Passes_on_multiple_relationship_paths() modelBuilder.Entity().HasOne().WithOne().HasForeignKey(a => a.Id).HasPrincipalKey(b => b.Id).IsRequired(); modelBuilder.Entity().HasOne().WithOne().HasForeignKey(a => a.Id).HasPrincipalKey(b => b.Id).IsRequired(); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalFact] @@ -340,13 +359,14 @@ public virtual void Passes_on_redundant_foreign_key() VerifyWarning( CoreResources.LogRedundantForeignKey(new TestLogger()).GenerateMessage("{'Id'}", "A"), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] public virtual void Passes_on_escapable_foreign_key_cycles() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; var entityA = model.AddEntityType(typeof(A)); SetPrimaryKey(entityA); @@ -369,13 +389,14 @@ public virtual void Passes_on_escapable_foreign_key_cycles() CreateForeignKey(keyB1, keyA1); CreateForeignKey(keyA2, keyB2); - Validate(model); + Validate(modelBuilder); } [ConditionalFact] public virtual void Passes_on_escapable_foreign_key_cycles_not_starting_at_hub() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; var entityA = model.AddEntityType(typeof(A)); SetPrimaryKey(entityA); @@ -399,13 +420,14 @@ public virtual void Passes_on_escapable_foreign_key_cycles_not_starting_at_hub() CreateForeignKey(keyB1, keyA1); CreateForeignKey(keyB2, keyA2); - Validate(model); + Validate(modelBuilder); } [ConditionalFact] public virtual void Passes_on_foreign_key_cycle_with_one_GenerateOnAdd() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; var entityA = model.AddEntityType(typeof(A)); SetPrimaryKey(entityA); @@ -428,13 +450,14 @@ public virtual void Passes_on_foreign_key_cycle_with_one_GenerateOnAdd() keyA.Properties[0].ValueGenerated = ValueGenerated.OnAdd; - Validate(model); + Validate(modelBuilder); } [ConditionalFact] public virtual void Passes_on_double_reference_to_root_principal_property() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; var entityA = model.AddEntityType(typeof(A)); SetPrimaryKey(entityA); @@ -457,13 +480,14 @@ public virtual void Passes_on_double_reference_to_root_principal_property() CreateForeignKey(keyA1, keyB1); CreateForeignKey(keyA2, keyB2); - Validate(model); + Validate(modelBuilder); } [ConditionalFact] public virtual void Passes_on_diamond_path_to_root_principal_property() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; var entityA = model.AddEntityType(typeof(A)); SetPrimaryKey(entityA); @@ -491,7 +515,7 @@ public virtual void Passes_on_diamond_path_to_root_principal_property() CreateForeignKey(keyB1, keyA3); CreateForeignKey(keyB2, keyA4); - Validate(model); + Validate(modelBuilder); } [ConditionalFact] @@ -501,31 +525,33 @@ public virtual void Passes_on_correct_inheritance() modelBuilder.Entity(); modelBuilder.Entity(); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalFact] public virtual void Detects_skipped_base_type() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; var entityA = model.AddEntityType(typeof(A)); SetPrimaryKey(entityA); AddProperties(entityA); - var entityD = model.AddEntityType(typeof(D)); - SetBaseType(entityD, entityA); + var entityD = modelBuilder.Entity(); + entityD.HasBaseType(); - var entityF = model.AddEntityType(typeof(F)); - SetBaseType(entityF, entityA); + var entityF = modelBuilder.Entity(); + entityF.HasBaseType(); - VerifyError(CoreStrings.InconsistentInheritance(nameof(F), nameof(A), nameof(D)), model); + VerifyError(CoreStrings.InconsistentInheritance(nameof(F), nameof(A), nameof(D)), modelBuilder); } [ConditionalFact] public virtual void Detects_abstract_leaf_type() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; var entityA = model.AddEntityType(typeof(A)); SetPrimaryKey(entityA); @@ -534,13 +560,14 @@ public virtual void Detects_abstract_leaf_type() var entityAbstract = model.AddEntityType(typeof(Abstract)); SetBaseType(entityAbstract, entityA); - VerifyError(CoreStrings.AbstractLeafEntityType(entityAbstract.DisplayName()), model); + VerifyError(CoreStrings.AbstractLeafEntityType(entityAbstract.DisplayName()), modelBuilder); } [ConditionalFact] public virtual void Detects_generic_leaf_type() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; var entityAbstract = model.AddEntityType(typeof(Abstract)); SetPrimaryKey(entityAbstract); @@ -549,7 +576,7 @@ public virtual void Detects_generic_leaf_type() var entityGeneric = model.AddEntityType(typeof(Generic<>)); SetBaseType(entityGeneric, entityAbstract); - VerifyError(CoreStrings.AbstractLeafEntityType(entityGeneric.DisplayName()), model); + VerifyError(CoreStrings.AbstractLeafEntityType(entityGeneric.DisplayName()), modelBuilder); } [ConditionalFact] @@ -579,7 +606,7 @@ public virtual void Passes_on_valid_many_to_many_navigations() productsNavigation.SetInverse(ordersNavigation); ordersNavigation.SetInverse(productsNavigation); - Validate(model); + Validate(modelBuilder); } [ConditionalFact] @@ -603,7 +630,7 @@ public virtual void Detects_missing_foreign_key_for_skip_navigations() VerifyError( CoreStrings.SkipNavigationNoForeignKey(nameof(Order.Products), nameof(Order)), - model); + modelBuilder); } [ConditionalFact] @@ -628,7 +655,7 @@ public virtual void Detects_missing_inverse_skip_navigations() VerifyError( CoreStrings.SkipNavigationNoInverse(nameof(Order.Products), nameof(Order)), - model); + modelBuilder); } [ConditionalFact] @@ -648,13 +675,14 @@ public virtual void Detects_nonCollection_skip_navigations() VerifyError( CoreStrings.SkipNavigationNonCollection(nameof(OrderDetails.Customer), nameof(OrderDetails)), - model); + modelBuilder); } [ConditionalFact] public virtual void Passes_on_valid_owned_entity_types() { - var modelBuilder = CreateConventionlessInternalModelBuilder(); + var builder = CreateConventionlessModelBuilder(); + var modelBuilder = (InternalModelBuilder)builder.GetInfrastructure(); var entityTypeBuilder = modelBuilder.Entity(typeof(SampleEntity), ConfigurationSource.Convention); entityTypeBuilder.PrimaryKey(new[] { nameof(SampleEntity.Id) }, ConfigurationSource.Convention); entityTypeBuilder.Ignore(nameof(SampleEntity.Name), ConfigurationSource.Explicit); @@ -669,13 +697,14 @@ public virtual void Passes_on_valid_owned_entity_types() ownedTypeBuilder.Ignore(nameof(ReferencedEntity.Id), ConfigurationSource.Explicit); ownedTypeBuilder.Ignore(nameof(ReferencedEntity.SampleEntityId), ConfigurationSource.Explicit); - Validate(modelBuilder.Metadata); + Validate(builder); } [ConditionalFact] public virtual void Detects_entity_type_with_multiple_ownerships() { - var modelBuilder = CreateConventionlessInternalModelBuilder(); + var builder = CreateConventionlessModelBuilder(); + var modelBuilder = (InternalModelBuilder)builder.GetInfrastructure(); var entityTypeBuilder = modelBuilder.Entity(typeof(SampleEntity), ConfigurationSource.Convention); entityTypeBuilder.PrimaryKey(new[] { nameof(SampleEntity.Id) }, ConfigurationSource.Convention); @@ -698,13 +727,14 @@ public virtual void Detects_entity_type_with_multiple_ownerships() VerifyError( CoreStrings.MultipleOwnerships(nameof(ReferencedEntity), "'SampleEntity.ReferencedEntity', 'SampleEntity.'"), - modelBuilder.Metadata); + builder); } [ConditionalFact] public virtual void Detects_principal_owned_entity_type() { - var modelBuilder = CreateConventionlessInternalModelBuilder(); + var builder = CreateConventionlessModelBuilder(); + var modelBuilder = (InternalModelBuilder)builder.GetInfrastructure(); var entityTypeBuilder = modelBuilder.Entity(typeof(SampleEntity), ConfigurationSource.Convention); entityTypeBuilder.PrimaryKey(new[] { nameof(SampleEntity.Id) }, ConfigurationSource.Convention); @@ -732,13 +762,14 @@ public virtual void Detects_principal_owned_entity_type() nameof(AnotherSampleEntity) + "." + nameof(AnotherSampleEntity.ReferencedEntity), nameof(ReferencedEntity), nameof(ReferencedEntity)), - modelBuilder.Metadata); + builder); } [ConditionalFact] public virtual void Detects_non_owner_navigation_to_owned_entity_type() { - var modelBuilder = CreateConventionlessInternalModelBuilder(); + var builder = CreateConventionlessModelBuilder(); + var modelBuilder = (InternalModelBuilder)builder.GetInfrastructure(); var entityTypeBuilder = modelBuilder.Entity(typeof(SampleEntity), ConfigurationSource.Convention); entityTypeBuilder.PrimaryKey(new[] { nameof(SampleEntity.Id) }, ConfigurationSource.Convention); @@ -764,13 +795,14 @@ public virtual void Detects_non_owner_navigation_to_owned_entity_type() VerifyError( CoreStrings.InverseToOwnedType( nameof(AnotherSampleEntity), nameof(SampleEntity.ReferencedEntity), nameof(ReferencedEntity), nameof(SampleEntity)), - modelBuilder.Metadata); + builder); } [ConditionalFact] public virtual void Detects_derived_owned_entity_type() { - var modelBuilder = CreateConventionlessInternalModelBuilder(); + var builder = CreateConventionlessModelBuilder(); + var modelBuilder = (InternalModelBuilder)builder.GetInfrastructure(); var entityTypeBuilder = modelBuilder.Entity(typeof(B), ConfigurationSource.Convention); entityTypeBuilder.PrimaryKey(new[] { nameof(B.Id) }, ConfigurationSource.Convention); @@ -794,13 +826,14 @@ public virtual void Detects_derived_owned_entity_type() ownedTypeBuilder.HasBaseType(typeof(A), ConfigurationSource.Convention); - VerifyError(CoreStrings.OwnedDerivedType(nameof(D)), modelBuilder.Metadata); + VerifyError(CoreStrings.OwnedDerivedType(nameof(D)), builder); } [ConditionalFact] public virtual void Detects_owned_entity_type_without_ownership() { - var modelBuilder = CreateConventionlessInternalModelBuilder(); + var builder = CreateConventionlessModelBuilder(); + var modelBuilder = (InternalModelBuilder)builder.GetInfrastructure(); var aBuilder = modelBuilder.Entity(typeof(A), ConfigurationSource.Convention); aBuilder.Ignore(nameof(A.Id), ConfigurationSource.Explicit); aBuilder.Ignore(nameof(A.P0), ConfigurationSource.Explicit); @@ -810,7 +843,7 @@ public virtual void Detects_owned_entity_type_without_ownership() modelBuilder.Owned(typeof(A), ConfigurationSource.Convention); - VerifyError(CoreStrings.OwnerlessOwnedType(nameof(A)), modelBuilder.Metadata); + VerifyError(CoreStrings.OwnerlessOwnedType(nameof(A)), builder); } [ConditionalFact] @@ -827,7 +860,7 @@ public virtual void Detects_ForeignKey_on_inherited_generated_key_property() "SomeId", "Generic", "{'SomeId'}", - nameof(Abstract)), modelBuilder.Model); + nameof(Abstract)), modelBuilder); } [ConditionalFact] @@ -837,7 +870,7 @@ public virtual void Passes_for_ForeignKey_on_inherited_generated_key_property_ab modelBuilder.Entity().Property(e => e.Id).ValueGeneratedOnAdd(); modelBuilder.Entity>().HasOne().WithOne().HasForeignKey>(e => e.Id); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalFact] @@ -850,7 +883,7 @@ public virtual void Passes_for_ForeignKey_on_inherited_generated_composite_key_p modelBuilder.Entity>().HasOne().WithOne().HasForeignKey>("SomeId"); modelBuilder.Entity>(); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalTheory] @@ -859,7 +892,9 @@ public virtual void Passes_for_ForeignKey_on_inherited_generated_composite_key_p [InlineData(ChangeTrackingStrategy.ChangingAndChangedNotificationsWithOriginalValues)] public virtual void Detects_non_notifying_entities(ChangeTrackingStrategy changeTrackingStrategy) { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; + var entityType = model.AddEntityType(typeof(NonNotifyingEntity)); var id = entityType.AddProperty("Id"); entityType.SetPrimaryKey(id); @@ -868,7 +903,7 @@ public virtual void Detects_non_notifying_entities(ChangeTrackingStrategy change VerifyError( CoreStrings.ChangeTrackingInterfaceMissing("NonNotifyingEntity", changeTrackingStrategy, "INotifyPropertyChanged"), - model); + modelBuilder); } [ConditionalTheory] @@ -876,7 +911,9 @@ public virtual void Detects_non_notifying_entities(ChangeTrackingStrategy change [InlineData(ChangeTrackingStrategy.ChangingAndChangedNotificationsWithOriginalValues)] public virtual void Detects_changed_only_notifying_entities(ChangeTrackingStrategy changeTrackingStrategy) { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; + var entityType = model.AddEntityType(typeof(ChangedOnlyEntity)); var id = entityType.AddProperty("Id"); entityType.SetPrimaryKey(id); @@ -885,7 +922,7 @@ public virtual void Detects_changed_only_notifying_entities(ChangeTrackingStrate VerifyError( CoreStrings.ChangeTrackingInterfaceMissing("ChangedOnlyEntity", changeTrackingStrategy, "INotifyPropertyChanging"), - model); + modelBuilder); } [ConditionalTheory] @@ -895,14 +932,16 @@ public virtual void Detects_changed_only_notifying_entities(ChangeTrackingStrate [InlineData(ChangeTrackingStrategy.ChangingAndChangedNotificationsWithOriginalValues)] public virtual void Passes_for_fully_notifying_entities(ChangeTrackingStrategy changeTrackingStrategy) { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; + var entityType = model.AddEntityType(typeof(FullNotificationEntity)); var id = entityType.AddProperty("Id"); entityType.SetPrimaryKey(id); model.SetChangeTrackingStrategy(changeTrackingStrategy); - Validate(model); + Validate(modelBuilder); } [ConditionalTheory] @@ -911,27 +950,31 @@ public virtual void Passes_for_fully_notifying_entities(ChangeTrackingStrategy c public virtual void Passes_for_changed_only_entities_with_snapshot_or_changed_only_tracking( ChangeTrackingStrategy changeTrackingStrategy) { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; + var entityType = model.AddEntityType(typeof(ChangedOnlyEntity)); var id = entityType.AddProperty("Id"); entityType.SetPrimaryKey(id); model.SetChangeTrackingStrategy(changeTrackingStrategy); - Validate(model); + Validate(modelBuilder); } [ConditionalFact] public virtual void Passes_for_non_notifying_entities_with_snapshot_tracking() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; + var entityType = model.AddEntityType(typeof(NonNotifyingEntity)); var id = entityType.AddProperty("Id"); entityType.SetPrimaryKey(id); model.SetChangeTrackingStrategy(ChangeTrackingStrategy.Snapshot); - Validate(model); + Validate(modelBuilder); } [ConditionalFact] @@ -943,11 +986,11 @@ public virtual void Passes_for_valid_seeds() modelBuilder.Entity().HasData( new D { Id = 2, P0 = 3 }); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalFact] - public virtual void Passes_for_ignored_invalid_properties() + public virtual void Passes_for_ignored_invalid_seeded_properties() { var modelBuilder = CreateConventionalModelBuilder(); modelBuilder.Entity( @@ -970,7 +1013,7 @@ public virtual void Passes_for_ignored_invalid_properties() }); }); - Validate(modelBuilder.Model); + Validate(modelBuilder); var data = modelBuilder.Model.GetEntityTypes().Single().GetSeedData(); Assert.Equal(-1, data.First().Values.Single()); @@ -1018,7 +1061,7 @@ public virtual void Detects_missing_required_values_in_seeds() VerifyError( CoreStrings.SeedDatumMissingValue(nameof(A), nameof(A.P0)), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1033,7 +1076,7 @@ public virtual void Passes_on_missing_required_store_generated_values_in_seeds() new A { Id = 1 }); }); - Validate(modelBuilder.Model); + Validate(modelBuilder); } [ConditionalFact] @@ -1049,7 +1092,7 @@ public virtual void Detects_missing_key_values_in_seeds() .ValueGenerated); VerifyError( CoreStrings.SeedDatumDefaultValue(nameof(NonSignedIntegerKeyEntity), nameof(NonSignedIntegerKeyEntity.Id), entity.Id), - modelBuilder.Model); + modelBuilder); } [ConditionalFact] @@ -1060,7 +1103,7 @@ public virtual void Detects_missing_signed_integer_key_values_in_seeds() VerifyError( CoreStrings.SeedDatumSignedNumericValue(nameof(A), nameof(A.Id)), - modelBuilder.Model); + modelBuilder); } [ConditionalTheory] @@ -1078,7 +1121,7 @@ public virtual void Detects_duplicate_seeds(bool sensitiveDataLoggingEnabled) sensitiveDataLoggingEnabled ? CoreStrings.SeedDatumDuplicateSensitive(nameof(D), $"{nameof(A.Id)}:1") : CoreStrings.SeedDatumDuplicate(nameof(D), $"{{'{nameof(A.Id)}'}}"), - modelBuilder.Model, + modelBuilder, sensitiveDataLoggingEnabled); } @@ -1099,7 +1142,7 @@ public virtual void Detects_incompatible_values(bool sensitiveDataLoggingEnabled sensitiveDataLoggingEnabled ? CoreStrings.SeedDatumIncompatibleValueSensitive(nameof(A), "invalid", nameof(A.P0), "int?") : CoreStrings.SeedDatumIncompatibleValue(nameof(A), nameof(A.P0), "int?"), - modelBuilder.Model, + modelBuilder, sensitiveDataLoggingEnabled); } @@ -1129,7 +1172,7 @@ public virtual void Detects_reference_navigations_in_seeds(bool sensitiveDataLog nameof(SampleEntity.ReferencedEntity), nameof(ReferencedEntity), $"{{'{nameof(ReferencedEntity.SampleEntityId)}'}}"), - modelBuilder.Model, + modelBuilder, sensitiveDataLoggingEnabled); } @@ -1161,7 +1204,7 @@ public virtual void Detects_reference_navigations_in_seeds2(bool sensitiveDataLo nameof(Order.Products), "OrderProduct (Dictionary)", "{'OrdersId'}"), - modelBuilder.Model, + modelBuilder, sensitiveDataLoggingEnabled); } @@ -1196,14 +1239,15 @@ public virtual void Detects_collection_navigations_in_seeds(bool sensitiveDataLo nameof(SampleEntity.OtherSamples), nameof(SampleEntity), "{'SampleEntityId'}"), - modelBuilder.Model, + modelBuilder, sensitiveDataLoggingEnabled); } [ConditionalFact] public virtual void Detects_missing_discriminator_property() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; var entityA = model.AddEntityType(typeof(A)); SetPrimaryKey(entityA); @@ -1212,13 +1256,14 @@ public virtual void Detects_missing_discriminator_property() var entityC = model.AddEntityType(typeof(C)); entityC.BaseType = entityA; - VerifyError(CoreStrings.NoDiscriminatorProperty(entityA.DisplayName()), model); + VerifyError(CoreStrings.NoDiscriminatorProperty(entityA.DisplayName()), modelBuilder); } [ConditionalFact] public virtual void Detects_missing_discriminator_value_on_base() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; var entityA = model.AddEntityType(typeof(A)); SetPrimaryKey(entityA); @@ -1230,13 +1275,14 @@ public virtual void Detects_missing_discriminator_value_on_base() entityA.SetDiscriminatorProperty(entityA.AddProperty("D", typeof(int))); entityC.SetDiscriminatorValue(1); - VerifyError(CoreStrings.NoDiscriminatorValue(entityA.DisplayName()), model); + VerifyError(CoreStrings.NoDiscriminatorValue(entityA.DisplayName()), modelBuilder); } [ConditionalFact] public virtual void Detects_missing_discriminator_value_on_leaf() { - var model = CreateConventionlessModelBuilder().Model; + var modelBuilder = CreateConventionlessModelBuilder(); + var model = modelBuilder.Model; var entityAbstract = model.AddEntityType(typeof(Abstract)); SetPrimaryKey(entityAbstract); @@ -1248,7 +1294,7 @@ public virtual void Detects_missing_discriminator_value_on_leaf() entityAbstract.SetDiscriminatorProperty(entityAbstract.AddProperty("D", typeof(int))); entityAbstract.SetDiscriminatorValue(0); - VerifyError(CoreStrings.NoDiscriminatorValue(entityGeneric.DisplayName()), model); + VerifyError(CoreStrings.NoDiscriminatorValue(entityGeneric.DisplayName()), modelBuilder); } [ConditionalFact] @@ -1260,8 +1306,7 @@ public virtual void Detects_missing_non_string_discriminator_values() .HasValue(0) .HasValue(1); - var model = modelBuilder.Model; - VerifyError(CoreStrings.NoDiscriminatorValue(typeof(C).Name), model); + VerifyError(CoreStrings.NoDiscriminatorValue(typeof(C).Name), modelBuilder); } [ConditionalFact] @@ -1273,8 +1318,7 @@ public virtual void Detects_duplicate_discriminator_values() .HasValue(1) .HasValue(2); - var model = modelBuilder.Model; - VerifyError(CoreStrings.DuplicateDiscriminatorValue(typeof(C).Name, 1, typeof(A).Name), model); + VerifyError(CoreStrings.DuplicateDiscriminatorValue(typeof(C).Name, 1, typeof(A).Name), modelBuilder); } [ConditionalFact] @@ -1283,11 +1327,12 @@ public virtual void Required_navigation_with_query_filter_on_one_side_issues_a_w var modelBuilder = CreateConventionalModelBuilder(); modelBuilder.Entity().HasMany(x => x.Orders).WithOne(x => x.Customer).IsRequired(); modelBuilder.Entity().HasQueryFilter(x => x.Id > 5); + modelBuilder.Ignore(); var message = CoreResources.LogPossibleIncorrectRequiredNavigationWithQueryFilterInteraction( CreateValidationLogger()).GenerateMessage(nameof(Customer), nameof(Order)); - VerifyWarning(message, modelBuilder.Model); + VerifyWarning(message, modelBuilder); } [ConditionalFact] @@ -1300,7 +1345,7 @@ public virtual void Optional_navigation_with_query_filter_on_one_side_doesnt_iss var message = CoreResources.LogPossibleIncorrectRequiredNavigationWithQueryFilterInteraction( CreateValidationLogger()).GenerateMessage(nameof(Customer), nameof(Order)); - VerifyLogDoesNotContain(message, modelBuilder.Model); + VerifyLogDoesNotContain(message, modelBuilder); } [ConditionalFact] @@ -1314,7 +1359,7 @@ public virtual void Required_navigation_with_query_filter_on_both_sides_doesnt_i var message = CoreResources.LogPossibleIncorrectRequiredNavigationWithQueryFilterInteraction( CreateValidationLogger()).GenerateMessage(nameof(Customer), nameof(Order)); - VerifyLogDoesNotContain(message, modelBuilder.Model); + VerifyLogDoesNotContain(message, modelBuilder); } [ConditionalFact] @@ -1324,7 +1369,7 @@ public virtual void Shared_type_inheritance_throws() modelBuilder.SharedTypeEntity("Shared1"); modelBuilder.SharedTypeEntity("Shared2").HasBaseType("Shared1"); - VerifyError(CoreStrings.SharedTypeDerivedType("Shared2 (C)"), modelBuilder.Model); + VerifyError(CoreStrings.SharedTypeDerivedType("Shared2 (C)"), modelBuilder); } [ConditionalFact] @@ -1342,11 +1387,11 @@ public virtual void Seeding_keyless_entity_throws() }); }); - VerifyError(CoreStrings.SeedKeylessEntity(nameof(KeylessSeed)), modelBuilder.Model); + VerifyError(CoreStrings.SeedKeylessEntity(nameof(KeylessSeed)), modelBuilder); } // INotify interfaces not really implemented; just marking the classes to test metadata construction - private class FullNotificationEntity : INotifyPropertyChanging, INotifyPropertyChanged + protected class FullNotificationEntity : INotifyPropertyChanging, INotifyPropertyChanged { public int Id { get; set; } @@ -1357,7 +1402,7 @@ private class FullNotificationEntity : INotifyPropertyChanging, INotifyPropertyC } // INotify interfaces not really implemented; just marking the classes to test metadata construction - private class ChangedOnlyEntity : INotifyPropertyChanged + protected class ChangedOnlyEntity : INotifyPropertyChanged { public int Id { get; set; } @@ -1366,12 +1411,12 @@ private class ChangedOnlyEntity : INotifyPropertyChanged #pragma warning restore 67 } - private class NonNotifyingEntity + protected class NonNotifyingEntity { public int Id { get; set; } } - private class NonSignedIntegerKeyEntity + protected class NonSignedIntegerKeyEntity { public uint Id { get; set; } } diff --git a/test/EFCore.Tests/Infrastructure/ModelValidatorTestBase.cs b/test/EFCore.Tests/Infrastructure/ModelValidatorTestBase.cs index 3426d019ee1..cd4ff06b5ef 100644 --- a/test/EFCore.Tests/Infrastructure/ModelValidatorTestBase.cs +++ b/test/EFCore.Tests/Infrastructure/ModelValidatorTestBase.cs @@ -7,14 +7,10 @@ using System.Diagnostics; using System.Linq; using System.Reflection; -using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Diagnostics.Internal; using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Metadata.Conventions; -using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.EntityFrameworkCore.TestUtilities; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Xunit; @@ -256,17 +252,17 @@ protected ModelValidatorTestBase() protected ListLoggerFactory LoggerFactory { get; } - protected virtual void VerifyWarning(string expectedMessage, IMutableModel model, LogLevel level = LogLevel.Warning) + protected virtual void VerifyWarning(string expectedMessage, TestHelpers.TestModelBuilder modelBuilder, LogLevel level = LogLevel.Warning) { - Validate(model); + Validate(modelBuilder); var logEntry = LoggerFactory.Log.Single(l => l.Level == level); Assert.Equal(expectedMessage, logEntry.Message); } - protected virtual void VerifyWarnings(string[] expectedMessages, IMutableModel model, LogLevel level = LogLevel.Warning) + protected virtual void VerifyWarnings(string[] expectedMessages, TestHelpers.TestModelBuilder modelBuilder, LogLevel level = LogLevel.Warning) { - Validate(model); + Validate(modelBuilder); var logEntries = LoggerFactory.Log.Where(l => l.Level == level); Assert.Equal(expectedMessages.Length, logEntries.Count()); @@ -277,29 +273,23 @@ protected virtual void VerifyWarnings(string[] expectedMessages, IMutableModel m } } - protected virtual void VerifyError(string expectedMessage, IMutableModel model, bool sensitiveDataLoggingEnabled = false) + protected virtual void VerifyError(string expectedMessage, TestHelpers.TestModelBuilder modelBuilder, bool sensitiveDataLoggingEnabled = false) { - var message = Assert.Throws(() => Validate(model, sensitiveDataLoggingEnabled)).Message; + var message = Assert.Throws(() => Validate(modelBuilder, sensitiveDataLoggingEnabled)).Message; Assert.Equal(expectedMessage, message); } - protected virtual void VerifyLogDoesNotContain(string expectedMessage, IMutableModel model) + protected virtual void VerifyLogDoesNotContain(string expectedMessage, TestHelpers.TestModelBuilder modelBuilder) { - Validate(model); + Validate(modelBuilder); var logEntries = LoggerFactory.Log.Where(l => l.Message.Contains(expectedMessage)); Assert.Empty(logEntries); } - protected virtual IModel Validate(IMutableModel model, bool sensitiveDataLoggingEnabled = false) - { - var serviceProvider = CreateServiceProvider(sensitiveDataLoggingEnabled); - var modelRuntimeInitializer = serviceProvider.GetRequiredService(); - var validationLogger = CreateValidationLogger(sensitiveDataLoggingEnabled); - - return modelRuntimeInitializer.Initialize((IModel)model, designTime: true, validationLogger); - } + protected virtual IModel Validate(TestHelpers.TestModelBuilder modelBuilder, bool sensitiveDataLoggingEnabled = false) + => modelBuilder.FinalizeModel(designTime: true); protected DiagnosticsLogger CreateValidationLogger(bool sensitiveDataLoggingEnabled = false) { @@ -325,25 +315,14 @@ protected DiagnosticsLogger CreateModelLogger(bool sensi new NullDbContextLogger()); } - protected virtual ModelBuilder CreateConventionalModelBuilder(bool sensitiveDataLoggingEnabled = false) + protected virtual TestHelpers.TestModelBuilder CreateConventionalModelBuilder(bool sensitiveDataLoggingEnabled = false) => TestHelpers.CreateConventionBuilder( CreateModelLogger(sensitiveDataLoggingEnabled), CreateValidationLogger(sensitiveDataLoggingEnabled)); - protected virtual ModelBuilder CreateConventionlessModelBuilder(bool sensitiveDataLoggingEnabled = false) - { - var serviceProvider = CreateServiceProvider(sensitiveDataLoggingEnabled); - return new ModelBuilder(new ConventionSet(), serviceProvider.GetRequiredService()); - } - - protected IServiceProvider CreateServiceProvider(bool sensitiveDataLoggingEnabled = false) - => TestHelpers.CreateContextServices( - new ServiceCollection() - .AddScoped>(_ => CreateModelLogger(sensitiveDataLoggingEnabled)) - .AddScoped>( - _ => CreateValidationLogger(sensitiveDataLoggingEnabled))); - - protected ProviderConventionSetBuilderDependencies CreateDependencies(bool sensitiveDataLoggingEnabled = false) - => CreateServiceProvider(sensitiveDataLoggingEnabled).GetRequiredService(); + protected virtual TestHelpers.TestModelBuilder CreateConventionlessModelBuilder(bool sensitiveDataLoggingEnabled = false) + => TestHelpers.CreateConventionBuilder( + CreateModelLogger(sensitiveDataLoggingEnabled), CreateValidationLogger(sensitiveDataLoggingEnabled), + configurationBuilder => configurationBuilder.RemoveAllConventions()); protected virtual TestHelpers TestHelpers => InMemoryTestHelpers.Instance; diff --git a/test/EFCore.Tests/Metadata/Internal/ClrPropertyGetterFactoryTest.cs b/test/EFCore.Tests/Metadata/Internal/ClrPropertyGetterFactoryTest.cs index 750568b26d7..08be21923b7 100644 --- a/test/EFCore.Tests/Metadata/Internal/ClrPropertyGetterFactoryTest.cs +++ b/test/EFCore.Tests/Metadata/Internal/ClrPropertyGetterFactoryTest.cs @@ -128,11 +128,13 @@ public PropertyAccessMode GetPropertyAccessMode() public void Delegate_getter_is_returned_for_IProperty_property() { var modelBuilder = CreateModelBuilder(); - var idProperty = modelBuilder.Entity().Property(e => e.Id).Metadata; - InMemoryTestHelpers.Instance.Finalize(modelBuilder); + modelBuilder.Entity().Property(e => e.Id); + var model = modelBuilder.FinalizeModel(); + + var idProperty = model.FindEntityType(typeof(Customer)).FindProperty(nameof(Customer.Id)); Assert.Equal( - 7, new ClrPropertyGetterFactory().Create((IPropertyBase)idProperty).GetClrValue( + 7, new ClrPropertyGetterFactory().Create(idProperty).GetClrValue( new Customer { Id = 7 })); } @@ -150,7 +152,7 @@ public void Delegate_getter_is_returned_for_IProperty_struct_property() var modelBuilder = CreateModelBuilder(); modelBuilder.Entity().Property(e => e.Id); var fuelProperty = modelBuilder.Entity().Property(e => e.Fuel).Metadata; - InMemoryTestHelpers.Instance.Finalize(modelBuilder); + modelBuilder.FinalizeModel(); Assert.Equal( new Fuel(1.0), @@ -174,13 +176,13 @@ public void Delegate_getter_is_returned_for_index_property() modelBuilder.Entity().Property(e => e.Id); var propertyA = modelBuilder.Entity().Metadata.AddIndexerProperty("PropertyA", typeof(string)); var propertyB = modelBuilder.Entity().Metadata.AddIndexerProperty("PropertyB", typeof(int)); - InMemoryTestHelpers.Instance.Finalize(modelBuilder); + modelBuilder.FinalizeModel(); Assert.Equal("ValueA", new ClrPropertyGetterFactory().Create((IPropertyBase)propertyA).GetClrValue(new IndexedClass { Id = 7 })); Assert.Equal(123, new ClrPropertyGetterFactory().Create((IPropertyBase)propertyB).GetClrValue(new IndexedClass { Id = 7 })); } - private static ModelBuilder CreateModelBuilder() + private static TestHelpers.TestModelBuilder CreateModelBuilder() => InMemoryTestHelpers.Instance.CreateConventionBuilder(); private class Customer diff --git a/test/EFCore.Tests/Metadata/MetadataBuilderTest.cs b/test/EFCore.Tests/Metadata/MetadataBuilderTest.cs index 7fef69d7c57..98aa9891a6f 100644 --- a/test/EFCore.Tests/Metadata/MetadataBuilderTest.cs +++ b/test/EFCore.Tests/Metadata/MetadataBuilderTest.cs @@ -24,7 +24,7 @@ public void Can_write_convention_model_builder_extension() .ModelBuilderExtension("V1") .ModelBuilderExtension("V2"); - Assert.IsType(returnedBuilder); + Assert.IsAssignableFrom(returnedBuilder); var model = builder.Model; @@ -222,7 +222,7 @@ public void Can_write_convention_model_builder_extension_with_common_name() .SharedNameExtension("V1") .SharedNameExtension("V2"); - Assert.IsType(returnedBuilder); + Assert.IsAssignableFrom(returnedBuilder); var model = builder.Model; diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericRelationshipStringTest.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericRelationshipStringTest.cs index f0327d8ba27..a2e8e45a5ed 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericRelationshipStringTest.cs +++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericRelationshipStringTest.cs @@ -18,32 +18,32 @@ public class ModelBuilderGenericRelationshipStringTest : ModelBuilderGenericTest { public class GenericOneToManyString : OneToManyTestBase { - protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers) - => new GenericStringTestModelBuilder(testHelpers); + protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers, Action? configure) + => new GenericStringTestModelBuilder(testHelpers, configure); } public class GenericManyToOneString : ManyToOneTestBase { - protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers) - => new GenericStringTestModelBuilder(testHelpers); + protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers, Action? configure) + => new GenericStringTestModelBuilder(testHelpers, configure); } public class GenericOneToOneString : OneToOneTestBase { - protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers) - => new GenericStringTestModelBuilder(testHelpers); + protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers, Action? configure) + => new GenericStringTestModelBuilder(testHelpers, configure); } public class GenericOwnedTypesString : OwnedTypesTestBase { - protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers) - => new GenericStringTestModelBuilder(testHelpers); + protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers, Action? configure) + => new GenericStringTestModelBuilder(testHelpers, configure); } private class GenericStringTestModelBuilder : TestModelBuilder { - public GenericStringTestModelBuilder(TestHelpers testHelpers) - : base(testHelpers) + public GenericStringTestModelBuilder(TestHelpers testHelpers, Action? configure) + : base(testHelpers, configure) { } diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericRelationshipTypeTest.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericRelationshipTypeTest.cs index c6f4405c51d..c648737c882 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericRelationshipTypeTest.cs +++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericRelationshipTypeTest.cs @@ -17,14 +17,14 @@ public class ModelBuilderGenericRelationshipTypeTest : ModelBuilderGenericTest { public class GenericOneToOneType : OneToOneTestBase { - protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers) - => new GenericTypeTestModelBuilder(testHelpers); + protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers, Action? configure) + => new GenericTypeTestModelBuilder(testHelpers, configure); } private class GenericTypeTestModelBuilder : TestModelBuilder { - public GenericTypeTestModelBuilder(TestHelpers testHelpers) - : base(testHelpers) + public GenericTypeTestModelBuilder(TestHelpers testHelpers, Action? configure) + : base(testHelpers, configure) { } diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs index 6585b8cb332..2acab8cdf65 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs +++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs @@ -62,8 +62,8 @@ public void Can_discover_large_models_through_navigations() public class GenericNonRelationship : NonRelationshipTestBase { - protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers) - => new GenericTestModelBuilder(testHelpers); + protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers, Action? configure) + => new GenericTestModelBuilder(testHelpers, configure); [ConditionalFact] public virtual void Changing_propertyInfo_updates_Property() @@ -81,44 +81,44 @@ public virtual void Changing_propertyInfo_updates_Property() public class GenericInheritance : InheritanceTestBase { - protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers) - => new GenericTestModelBuilder(testHelpers); + protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers, Action? configure) + => new GenericTestModelBuilder(testHelpers, configure); } public class GenericOwnedTypes : OwnedTypesTestBase { - protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers) - => new GenericTestModelBuilder(testHelpers); + protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers, Action? configure) + => new GenericTestModelBuilder(testHelpers, configure); } public class GenericOneToMany : OneToManyTestBase { - protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers) - => new GenericTestModelBuilder(testHelpers); + protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers, Action? configure) + => new GenericTestModelBuilder(testHelpers, configure); } public class GenericManyToOne : ManyToOneTestBase { - protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers) - => new GenericTestModelBuilder(testHelpers); + protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers, Action? configure) + => new GenericTestModelBuilder(testHelpers, configure); } public class GenericManyToMany : ManyToManyTestBase { - protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers) - => new GenericTestModelBuilder(testHelpers); + protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers, Action? configure) + => new GenericTestModelBuilder(testHelpers, configure); } public class GenericOneToOne : OneToOneTestBase { - protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers) - => new GenericTestModelBuilder(testHelpers); + protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers, Action? configure) + => new GenericTestModelBuilder(testHelpers, configure); } protected class GenericTestModelBuilder : TestModelBuilder { - public GenericTestModelBuilder(TestHelpers testHelpers) - : base(testHelpers) + public GenericTestModelBuilder(TestHelpers testHelpers, Action? configure) + : base(testHelpers, configure) { } @@ -511,7 +511,7 @@ public override TestPropertyBuilder UsePropertyAccessMode(PropertyAcc public override TestPropertyBuilder HasConversion() => new GenericTestPropertyBuilder(PropertyBuilder.HasConversion()); - public override TestPropertyBuilder HasConversion(Type providerClrType) + public override TestPropertyBuilder HasConversion(Type? providerClrType) => new GenericTestPropertyBuilder(PropertyBuilder.HasConversion(providerClrType)); public override TestPropertyBuilder HasConversion( @@ -525,16 +525,16 @@ public override TestPropertyBuilder HasConversion(Type providerClrTyp public override TestPropertyBuilder HasConversion(ValueConverter converter) => new GenericTestPropertyBuilder(PropertyBuilder.HasConversion(converter)); - public override TestPropertyBuilder HasConversion(ValueConverter converter) + public override TestPropertyBuilder HasConversion(ValueConverter? converter) => new GenericTestPropertyBuilder(PropertyBuilder.HasConversion(converter)); - public override TestPropertyBuilder HasConversion(ValueConverter converter, ValueComparer valueComparer) + public override TestPropertyBuilder HasConversion(ValueConverter? converter, ValueComparer? valueComparer) => new GenericTestPropertyBuilder(PropertyBuilder.HasConversion(converter, valueComparer)); public override TestPropertyBuilder HasConversion() => new GenericTestPropertyBuilder(PropertyBuilder.HasConversion()); - public override TestPropertyBuilder HasConversion(Type? converterType, Type? comparerType) + public override TestPropertyBuilder HasConversion(Type converterType, Type? comparerType) => new GenericTestPropertyBuilder(PropertyBuilder.HasConversion(converterType, comparerType)); PropertyBuilder IInfrastructure>.Instance diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericStringTest.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericStringTest.cs index d6d71c8d481..18532073b09 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericStringTest.cs +++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericStringTest.cs @@ -23,8 +23,8 @@ public class ModelBuilderNonGenericStringTest : ModelBuilderNonGenericTest { public class NonGenericStringOwnedTypes : OwnedTypesTestBase { - protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers) - => new NonGenericStringTestModelBuilder(testHelpers); + protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers, Action? configure) + => new NonGenericStringTestModelBuilder(testHelpers, configure); public override void Reconfiguring_owned_type_as_non_owned_throws() { @@ -57,26 +57,26 @@ public override void Can_configure_owned_type_collection_with_one_call_afterward public class NonGenericStringOneToManyType : OneToManyTestBase { - protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers) - => new NonGenericStringTestModelBuilder(testHelpers); + protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers, Action? configure) + => new NonGenericStringTestModelBuilder(testHelpers, configure); } public class NonGenericStringManyToOneType : ManyToOneTestBase { - protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers) - => new NonGenericStringTestModelBuilder(testHelpers); + protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers, Action? configure) + => new NonGenericStringTestModelBuilder(testHelpers, configure); } public class NonGenericStringOneToOneType : OneToOneTestBase { - protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers) - => new NonGenericStringTestModelBuilder(testHelpers); + protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers, Action? configure) + => new NonGenericStringTestModelBuilder(testHelpers, configure); } private class NonGenericStringTestModelBuilder : TestModelBuilder { - public NonGenericStringTestModelBuilder(TestHelpers testHelpers) - : base(testHelpers) + public NonGenericStringTestModelBuilder(TestHelpers testHelpers, Action? configure) + : base(testHelpers, configure) { } diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs index 5d3fc191a87..fc36aed2658 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs +++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs @@ -24,14 +24,14 @@ public class ModelBuilderNonGenericTest : ModelBuilderTest { public class NonGenericNonRelationship : NonRelationshipTestBase { - protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers) - => new NonGenericTestModelBuilder(testHelpers); + protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers, Action? configure) + => new NonGenericTestModelBuilder(testHelpers, configure); } public class NonGenericInheritance : InheritanceTestBase { - protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers) - => new NonGenericTestModelBuilder(testHelpers); + protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers, Action? configure) + => new NonGenericTestModelBuilder(testHelpers, configure); } public class NonGenericOwnedTypes : OwnedTypesTestBase @@ -48,8 +48,8 @@ public virtual void OwnsOne_HasOne_with_just_string_navigation_for_non_CLR_prope .HasOne("Snoop")).Message); } - protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers) - => new NonGenericTestModelBuilder(testHelpers); + protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers, Action? configure) + => new NonGenericTestModelBuilder(testHelpers, configure); } public class NonGenericOneToMany : OneToManyTestBase @@ -129,32 +129,32 @@ protected class ComplexCaseParent13108 public ICollection? Children { get; set; } } - protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers) - => new NonGenericTestModelBuilder(testHelpers); + protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers, Action? configure) + => new NonGenericTestModelBuilder(testHelpers, configure); } public class NonGenericManyToOne : ManyToOneTestBase { - protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers) - => new NonGenericTestModelBuilder(testHelpers); + protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers, Action? configure) + => new NonGenericTestModelBuilder(testHelpers, configure); } public class NonGenericManyToMany : ManyToManyTestBase { - protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers) - => new NonGenericTestModelBuilder(testHelpers); + protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers, Action? configure) + => new NonGenericTestModelBuilder(testHelpers, configure); } public class NonGenericOneToOne : OneToOneTestBase { - protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers) - => new NonGenericTestModelBuilder(testHelpers); + protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers, Action? configure) + => new NonGenericTestModelBuilder(testHelpers, configure); } private class NonGenericTestModelBuilder : TestModelBuilder { - public NonGenericTestModelBuilder(TestHelpers testHelpers) - : base(testHelpers) + public NonGenericTestModelBuilder(TestHelpers testHelpers, Action? configure) + : base(testHelpers, configure) { } @@ -588,7 +588,7 @@ public override TestPropertyBuilder UsePropertyAccessMode(PropertyAcc public override TestPropertyBuilder HasConversion() => new NonGenericTestPropertyBuilder(PropertyBuilder.HasConversion()); - public override TestPropertyBuilder HasConversion(Type providerClrType) + public override TestPropertyBuilder HasConversion(Type? providerClrType) => new NonGenericTestPropertyBuilder(PropertyBuilder.HasConversion(providerClrType)); public override TestPropertyBuilder HasConversion( @@ -601,16 +601,16 @@ public override TestPropertyBuilder HasConversion(Type providerClrTyp public override TestPropertyBuilder HasConversion(ValueConverter converter) => new NonGenericTestPropertyBuilder(PropertyBuilder.HasConversion(converter)); - public override TestPropertyBuilder HasConversion(ValueConverter converter) + public override TestPropertyBuilder HasConversion(ValueConverter? converter) => new NonGenericTestPropertyBuilder(PropertyBuilder.HasConversion(converter)); - public override TestPropertyBuilder HasConversion(ValueConverter converter, ValueComparer valueComparer) + public override TestPropertyBuilder HasConversion(ValueConverter? converter, ValueComparer? valueComparer) => new NonGenericTestPropertyBuilder(PropertyBuilder.HasConversion(converter, valueComparer)); public override TestPropertyBuilder HasConversion() => new NonGenericTestPropertyBuilder(PropertyBuilder.HasConversion()); - public override TestPropertyBuilder HasConversion(Type? converterType, Type? comparerType) + public override TestPropertyBuilder HasConversion(Type converterType, Type? comparerType) => new NonGenericTestPropertyBuilder(PropertyBuilder.HasConversion(converterType, comparerType)); PropertyBuilder IInfrastructure.Instance diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericUnqualifiedStringTest.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericUnqualifiedStringTest.cs index abaf90a9b28..86d5e5c6c38 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericUnqualifiedStringTest.cs +++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericUnqualifiedStringTest.cs @@ -18,14 +18,14 @@ public class ModelBuilderNonGenericUnqualifiedStringTest : ModelBuilderNonGeneri { public class NonGenericStringOneToOneType : OneToOneTestBase { - protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers) - => new NonGenericStringTestModelBuilder(testHelpers); + protected override TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers, Action? configure) + => new NonGenericStringTestModelBuilder(testHelpers, configure); } private class NonGenericStringTestModelBuilder : TestModelBuilder { - public NonGenericStringTestModelBuilder(TestHelpers testHelpers) - : base(testHelpers) + public NonGenericStringTestModelBuilder(TestHelpers testHelpers, Action? configure) + : base(testHelpers, configure) { } diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs index a433360395e..3535f9758b0 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs +++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs @@ -7,13 +7,11 @@ using System.Linq.Expressions; using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.Diagnostics.Internal; -using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Metadata.Builders; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Microsoft.EntityFrameworkCore.TestUtilities; using Microsoft.EntityFrameworkCore.ValueGeneration; -using Microsoft.Extensions.DependencyInjection; using Xunit; #nullable enable @@ -97,8 +95,8 @@ public abstract class ModelBuilderTestBase testIndexComparer); } - protected virtual TestModelBuilder CreateModelBuilder() - => CreateTestModelBuilder(InMemoryTestHelpers.Instance); + protected virtual TestModelBuilder CreateModelBuilder(Action? configure = null) + => CreateTestModelBuilder(InMemoryTestHelpers.Instance, configure); protected TestModelBuilder HobNobBuilder() { @@ -110,12 +108,12 @@ protected TestModelBuilder HobNobBuilder() return builder; } - protected abstract TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers); + protected abstract TestModelBuilder CreateTestModelBuilder(TestHelpers testHelpers, Action? configure); } public abstract class TestModelBuilder { - protected TestModelBuilder(TestHelpers testHelpers) + protected TestModelBuilder(TestHelpers testHelpers, Action? configure) { var options = new LoggingOptions(); options.Initialize(new DbContextOptionsBuilder().EnableSensitiveDataLogging(false).Options); @@ -135,16 +133,16 @@ protected TestModelBuilder(TestHelpers testHelpers) testHelpers.LoggingDefinitions, new NullDbContextLogger()); - ModelBuilder = testHelpers.CreateConventionBuilder(modelLogger, ValidationLogger); - TestHelpers = testHelpers; + ModelBuilder = testHelpers.CreateConventionBuilder( + modelLogger, + ValidationLogger, + configure == null ? null : c => configure(c)); } - protected virtual TestHelpers TestHelpers { get; } - public virtual IMutableModel Model => ModelBuilder.Model; - public ModelBuilder ModelBuilder { get; } + public TestHelpers.TestModelBuilder ModelBuilder { get; } public ListLoggerFactory ValidationLoggerFactory { get; } public ListLoggerFactory ModelLoggerFactory { get; } protected virtual DiagnosticsLogger ValidationLogger { get; } @@ -174,12 +172,7 @@ public TestModelBuilder HasAnnotation(string annotation, object? value) where TEntity : class; public virtual IModel FinalizeModel() - { - var serviceProvider = TestHelpers.CreateContextServices(); - var modelRuntimeInitializer = serviceProvider.GetRequiredService(); - - return modelRuntimeInitializer.Initialize((IModel)ModelBuilder.Model, designTime: true, ValidationLogger); - } + => ModelBuilder.FinalizeModel(designTime: true); public virtual string GetDisplayName(Type entityType) => entityType.Name; @@ -417,13 +410,13 @@ public abstract class TestPropertyBuilder Expression> convertFromProviderExpression); public abstract TestPropertyBuilder HasConversion(ValueConverter converter); - public abstract TestPropertyBuilder HasConversion(ValueConverter converter); - public abstract TestPropertyBuilder HasConversion(ValueConverter converter, ValueComparer valueComparer); + public abstract TestPropertyBuilder HasConversion(ValueConverter? converter); + public abstract TestPropertyBuilder HasConversion(ValueConverter? converter, ValueComparer? valueComparer); public abstract TestPropertyBuilder HasConversion() where TConverter : ValueConverter where TComparer : ValueComparer; - public abstract TestPropertyBuilder HasConversion(Type? converterType, Type? comparerType); + public abstract TestPropertyBuilder HasConversion(Type converterType, Type? comparerType); } public abstract class TestNavigationBuilder diff --git a/test/EFCore.Tests/ModelBuilding/ShadowEntityTypeTest.cs b/test/EFCore.Tests/ModelBuilding/ShadowEntityTypeTest.cs index 4094c2b1653..4b90cca642a 100644 --- a/test/EFCore.Tests/ModelBuilding/ShadowEntityTypeTest.cs +++ b/test/EFCore.Tests/ModelBuilding/ShadowEntityTypeTest.cs @@ -83,7 +83,7 @@ public virtual void Can_create_one_to_one_shadow_navigations_between_shadow_enti Assert.Equal( CoreStrings.EntityRequiresKey("Order (Dictionary)"), - Assert.Throws(() => InMemoryTestHelpers.Instance.Finalize(modelBuilder)).Message); + Assert.Throws(() => modelBuilder.FinalizeModel()).Message); } [ConditionalFact] @@ -101,7 +101,7 @@ public virtual void Can_create_one_to_many_shadow_navigations_between_shadow_ent Assert.Equal( CoreStrings.EntityRequiresKey("Customer (Dictionary)"), - Assert.Throws(() => InMemoryTestHelpers.Instance.Finalize(modelBuilder)).Message); + Assert.Throws(() => modelBuilder.FinalizeModel()).Message); } [ConditionalFact] @@ -127,7 +127,7 @@ public virtual void Cannot_create_shadow_navigation_between_non_shadow_entity_ty Assert.Throws(() => orderEntityType.HasOne(typeof(Customer), "CustomerNavigation")).Message); } - protected virtual ModelBuilder CreateModelBuilder() + protected virtual TestHelpers.TestModelBuilder CreateModelBuilder() => InMemoryTestHelpers.Instance.CreateConventionBuilder(); protected class Order diff --git a/test/EFCore.Tests/ValueGeneration/ValueGeneratorSelectorTest.cs b/test/EFCore.Tests/ValueGeneration/ValueGeneratorSelectorTest.cs index 3f7db80bc23..383143fcea5 100644 --- a/test/EFCore.Tests/ValueGeneration/ValueGeneratorSelectorTest.cs +++ b/test/EFCore.Tests/ValueGeneration/ValueGeneratorSelectorTest.cs @@ -93,7 +93,7 @@ private static IModel BuildModel(bool generateValues = true) property.ValueGenerated = generateValues ? ValueGenerated.OnAdd : ValueGenerated.Never; } - return InMemoryTestHelpers.Instance.Finalize(builder); + return builder.FinalizeModel(); } private class AnEntity