diff --git a/EFCore.Runtime.slnf b/EFCore.Runtime.slnf index 36e61760f7f..bccb747def4 100644 --- a/EFCore.Runtime.slnf +++ b/EFCore.Runtime.slnf @@ -20,7 +20,7 @@ "test\\EFCore.AspNet.Specification.Tests\\EFCore.AspNet.Specification.Tests.csproj", "test\\EFCore.AspNet.SqlServer.FunctionalTests\\EFCore.AspNet.SqlServer.FunctionalTests.csproj", "test\\EFCore.AspNet.Sqlite.FunctionalTests\\EFCore.AspNet.Sqlite.FunctionalTests.csproj", - "test\\EFCore.AspNet.InMemory.FunctionalTests\\EFCore.AspNet.InMemory.FunctionalTests.csproj" + "test\\EFCore.AspNet.InMemory.FunctionalTests\\EFCore.AspNet.InMemory.FunctionalTests.csproj", "test\\EFCore.Cosmos.FunctionalTests\\EFCore.Cosmos.FunctionalTests.csproj", "test\\EFCore.Cosmos.Tests\\EFCore.Cosmos.Tests.csproj", "test\\EFCore.CrossStore.FunctionalTests\\EFCore.CrossStore.FunctionalTests.csproj", diff --git a/src/EFCore.Design/Scaffolding/Internal/CSharpDbContextGenerator.cs b/src/EFCore.Design/Scaffolding/Internal/CSharpDbContextGenerator.cs index 3e21d3c4f05..effcf385165 100644 --- a/src/EFCore.Design/Scaffolding/Internal/CSharpDbContextGenerator.cs +++ b/src/EFCore.Design/Scaffolding/Internal/CSharpDbContextGenerator.cs @@ -696,13 +696,13 @@ private void GenerateRelationship(IForeignKey foreignKey, bool useDataAnnotation canUseDataAnnotations = false; lines.Add( $".{nameof(ReferenceReferenceBuilder.HasPrincipalKey)}" - + (foreignKey.IsUnique ? $"<{foreignKey.PrincipalEntityType.DisplayName()}>" : "") + + (foreignKey.IsUnique ? $"<{foreignKey.PrincipalEntityType.Name}>" : "") + $"({_code.Lambda(foreignKey.PrincipalKey.Properties, "p")})"); } lines.Add( $".{nameof(ReferenceReferenceBuilder.HasForeignKey)}" - + (foreignKey.IsUnique ? $"<{foreignKey.DeclaringEntityType.DisplayName()}>" : "") + + (foreignKey.IsUnique ? $"<{foreignKey.DeclaringEntityType.Name}>" : "") + $"({_code.Lambda(foreignKey.Properties, "d")})"); var defaultOnDeleteAction = foreignKey.IsRequired diff --git a/src/EFCore.Design/Scaffolding/Internal/CSharpEntityTypeGenerator.cs b/src/EFCore.Design/Scaffolding/Internal/CSharpEntityTypeGenerator.cs index 950844b6968..17ce96528d6 100644 --- a/src/EFCore.Design/Scaffolding/Internal/CSharpEntityTypeGenerator.cs +++ b/src/EFCore.Design/Scaffolding/Internal/CSharpEntityTypeGenerator.cs @@ -12,7 +12,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Metadata.Internal; -using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Utilities; namespace Microsoft.EntityFrameworkCore.Scaffolding.Internal diff --git a/src/EFCore.Design/Scaffolding/Internal/CSharpModelGenerator.cs b/src/EFCore.Design/Scaffolding/Internal/CSharpModelGenerator.cs index 0fa21e8e746..68f43ce7cf1 100644 --- a/src/EFCore.Design/Scaffolding/Internal/CSharpModelGenerator.cs +++ b/src/EFCore.Design/Scaffolding/Internal/CSharpModelGenerator.cs @@ -123,7 +123,7 @@ public override ScaffoldedModel GenerateModel( generatedCode = CSharpEntityTypeGenerator.WriteCode(entityType, options.ModelNamespace, options.UseDataAnnotations); // output EntityType poco .cs file - var entityTypeFileName = entityType.DisplayName() + FileExtension; + var entityTypeFileName = entityType.Name + FileExtension; resultingFiles.AdditionalFiles.Add( new ScaffoldedFile { Path = entityTypeFileName, Code = generatedCode }); } diff --git a/src/EFCore.Design/Scaffolding/Internal/RelationalScaffoldingModelFactory.cs b/src/EFCore.Design/Scaffolding/Internal/RelationalScaffoldingModelFactory.cs index a651dfa2a5b..63276031ba1 100644 --- a/src/EFCore.Design/Scaffolding/Internal/RelationalScaffoldingModelFactory.cs +++ b/src/EFCore.Design/Scaffolding/Internal/RelationalScaffoldingModelFactory.cs @@ -836,7 +836,7 @@ protected virtual IMutableForeignKey VisitForeignKey([NotNull] ModelBuilder mode DesignStrings.ForeignKeyScaffoldErrorPrincipalKeyNotFound( foreignKey.DisplayName(), string.Join(CultureInfo.CurrentCulture.TextInfo.ListSeparator, principalColumns), - principalEntityType.DisplayName())); + principalEntityType.Name)); return null; } diff --git a/src/EFCore.Relational/Migrations/Internal/MigrationsModelDiffer.cs b/src/EFCore.Relational/Migrations/Internal/MigrationsModelDiffer.cs index 164b6ad8037..d0f81edd566 100644 --- a/src/EFCore.Relational/Migrations/Internal/MigrationsModelDiffer.cs +++ b/src/EFCore.Relational/Migrations/Internal/MigrationsModelDiffer.cs @@ -1662,9 +1662,13 @@ protected virtual void TrackData( { foreach (var targetSeed in targetEntityType.GetSeedData()) { - _targetUpdateAdapter - .CreateEntry(targetSeed, targetEntityType) - .EntityState = EntityState.Added; + var targetEntry = _targetUpdateAdapter.CreateEntry(targetSeed, targetEntityType); + if (targetEntry.ToEntityEntry().Entity is Dictionary targetBag) + { + targetBag.Remove((key, _, target) => !target.ContainsKey(key), targetSeed); + } + + targetEntry.EntityState = EntityState.Added; } } diff --git a/src/EFCore.Relational/Update/Internal/ModificationCommandComparer.cs b/src/EFCore.Relational/Update/Internal/ModificationCommandComparer.cs index 14517311d54..d3350c934ee 100644 --- a/src/EFCore.Relational/Update/Internal/ModificationCommandComparer.cs +++ b/src/EFCore.Relational/Update/Internal/ModificationCommandComparer.cs @@ -65,8 +65,7 @@ public virtual int Compare(ModificationCommand x, ModificationCommand y) return result; } - if (xState != EntityState.Added - && x.Entries.Count > 0 + if (x.Entries.Count > 0 && y.Entries.Count > 0) { var xEntry = x.Entries[0]; @@ -83,15 +82,18 @@ public virtual int Compare(ModificationCommand x, ModificationCommand y) } } - var xKey = xEntry.EntityType.FindPrimaryKey(); - for (var i = 0; i < xKey.Properties.Count; i++) + if (xState != EntityState.Added) { - var xKeyProperty = xKey.Properties[i]; - - result = xKeyProperty.GetCurrentValueComparer().Compare(xEntry, yEntry); - if (result != 0) + var xKey = xEntry.EntityType.FindPrimaryKey(); + for (var i = 0; i < xKey.Properties.Count; i++) { - return result; + var xKeyProperty = xKey.Properties[i]; + + result = xKeyProperty.GetCurrentValueComparer().Compare(xEntry, yEntry); + if (result != 0) + { + return result; + } } } } diff --git a/src/EFCore/ChangeTracking/Internal/InternalEntityEntryFactory.cs b/src/EFCore/ChangeTracking/Internal/InternalEntityEntryFactory.cs index 6c65cbc1ce8..e6aa3a3b6f5 100644 --- a/src/EFCore/ChangeTracking/Internal/InternalEntityEntryFactory.cs +++ b/src/EFCore/ChangeTracking/Internal/InternalEntityEntryFactory.cs @@ -48,11 +48,6 @@ public virtual InternalEntityEntry Create( private static InternalEntityEntry NewInternalEntityEntry(IStateManager stateManager, IEntityType entityType, object entity) { - if (!entityType.HasClrType) - { - return new InternalShadowEntityEntry(stateManager, entityType); - } - Check.DebugAssert(entity != null, "entity is null"); return entityType.ShadowPropertyCount() > 0 @@ -65,12 +60,8 @@ private static InternalEntityEntry NewInternalEntityEntry( IEntityType entityType, object entity, in ValueBuffer valueBuffer) - { - return !entityType.HasClrType - ? new InternalShadowEntityEntry(stateManager, entityType, valueBuffer) - : entityType.ShadowPropertyCount() > 0 - ? (InternalEntityEntry)new InternalMixedEntityEntry(stateManager, entityType, entity, valueBuffer) - : new InternalClrEntityEntry(stateManager, entityType, entity); - } + => entityType.ShadowPropertyCount() > 0 + ? (InternalEntityEntry)new InternalMixedEntityEntry(stateManager, entityType, entity, valueBuffer) + : new InternalClrEntityEntry(stateManager, entityType, entity); } } diff --git a/src/EFCore/ChangeTracking/Internal/InternalShadowEntityEntry.cs b/src/EFCore/ChangeTracking/Internal/InternalShadowEntityEntry.cs deleted file mode 100644 index 1abedb85ddf..00000000000 --- a/src/EFCore/ChangeTracking/Internal/InternalShadowEntityEntry.cs +++ /dev/null @@ -1,161 +0,0 @@ -// 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.Collections.Generic; -using JetBrains.Annotations; -using Microsoft.EntityFrameworkCore.Internal; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Metadata.Internal; -using Microsoft.EntityFrameworkCore.Storage; - -namespace Microsoft.EntityFrameworkCore.ChangeTracking.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 class InternalShadowEntityEntry : InternalEntityEntry - { - private readonly ISnapshot _propertyValues; - - /// - /// 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 override object Entity - => null; - - /// - /// 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 InternalShadowEntityEntry( - [NotNull] IStateManager stateManager, - [NotNull] IEntityType entityType) - : base(stateManager, entityType) - { - _propertyValues = entityType.GetEmptyShadowValuesFactory()(); - - // ReSharper disable once DoNotCallOverridableMethodsInConstructor - MarkShadowPropertiesNotSet(entityType); - } - - /// - /// 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 InternalShadowEntityEntry( - [NotNull] IStateManager stateManager, - [NotNull] IEntityType entityType, - in ValueBuffer valueBuffer) - : base(stateManager, entityType) - { - _propertyValues = ((EntityType)entityType).ShadowValuesFactory(valueBuffer); - } - - /// - /// 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. - /// - protected override T ReadShadowValue(int shadowIndex) - => _propertyValues.GetValue(shadowIndex); - - /// - /// 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. - /// - protected override object ReadPropertyValue(IPropertyBase propertyBase) - => _propertyValues[propertyBase.GetShadowIndex()]; - - /// - /// 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. - /// - protected override bool PropertyHasDefaultValue(IPropertyBase propertyBase) - => propertyBase.ClrType.IsDefaultValue(_propertyValues[propertyBase.GetShadowIndex()]); - - /// - /// 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. - /// - protected override void WritePropertyValue(IPropertyBase propertyBase, object value, bool forMaterialization) - => _propertyValues[propertyBase.GetShadowIndex()] = value; - - /// - /// 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 override object GetOrCreateCollection(INavigationBase navigationBase, bool forMaterialization) - => GetOrCreateCollectionTyped(navigationBase); - - private ICollection GetOrCreateCollectionTyped(INavigationBase navigation) - { - if (!(_propertyValues[navigation.GetShadowIndex()] is ICollection collection)) - { - collection = new HashSet(); - _propertyValues[navigation.GetShadowIndex()] = collection; - } - - return collection; - } - - /// - /// 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 override bool CollectionContains(INavigationBase navigationBase, InternalEntityEntry value) - => GetOrCreateCollectionTyped(navigationBase).Contains(value.Entity); - - /// - /// 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 override bool AddToCollection(INavigationBase navigationBase, InternalEntityEntry value, bool forMaterialization) - { - if (navigationBase.TargetEntityType.ClrType == null) - { - return false; - } - - var collection = GetOrCreateCollectionTyped(navigationBase); - if (!collection.Contains(value.Entity)) - { - collection.Add(value.Entity); - return true; - } - - return false; - } - - /// - /// 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 override bool RemoveFromCollection(INavigationBase navigationBase, InternalEntityEntry value) - => GetOrCreateCollectionTyped(navigationBase).Remove(value.Entity); - } -} diff --git a/src/EFCore/ChangeTracking/Internal/StateManager.cs b/src/EFCore/ChangeTracking/Internal/StateManager.cs index 0e745a7d8b8..2190bdd7035 100644 --- a/src/EFCore/ChangeTracking/Internal/StateManager.cs +++ b/src/EFCore/ChangeTracking/Internal/StateManager.cs @@ -303,9 +303,7 @@ public virtual InternalEntityEntry CreateEntry(IDictionary value } var valueBuffer = new ValueBuffer(valuesArray); - var entity = entityType.HasClrType - ? EntityMaterializerSource.GetMaterializer(entityType)(new MaterializationContext(valueBuffer, Context)) - : null; + var entity = EntityMaterializerSource.GetMaterializer(entityType)(new MaterializationContext(valueBuffer, Context)); var shadowPropertyValueBuffer = new ValueBuffer(shadowPropertyValuesArray); var entry = _internalEntityEntryFactory.Create(this, entityType, entity, shadowPropertyValueBuffer); diff --git a/src/EFCore/Extensions/EntityTypeExtensions.cs b/src/EFCore/Extensions/EntityTypeExtensions.cs index a7ee05696b3..b65be11cd93 100644 --- a/src/EFCore/Extensions/EntityTypeExtensions.cs +++ b/src/EFCore/Extensions/EntityTypeExtensions.cs @@ -330,11 +330,6 @@ public static IEnumerable GetDeclaredIndexes([NotNull] this IEntityType [DebuggerStepThrough] public static string DisplayName([NotNull] this ITypeBase type) { - if (type.ClrType == null) - { - return type.Name; - } - if (!type.HasSharedClrType) { return type.ClrType.ShortDisplayName(); diff --git a/src/EFCore/Infrastructure/ModelValidator.cs b/src/EFCore/Infrastructure/ModelValidator.cs index 377ea2cc491..14f3d3d0a7f 100644 --- a/src/EFCore/Infrastructure/ModelValidator.cs +++ b/src/EFCore/Infrastructure/ModelValidator.cs @@ -53,7 +53,9 @@ public virtual void Validate(IModel model, IDiagnosticsLogger /// The model to validate. /// The logger to use. + [Obsolete("Shadow entity types cannot be created anymore")] protected virtual void ValidateNoShadowEntities( [NotNull] IModel model, [NotNull] IDiagnosticsLogger logger) { - Check.NotNull(model, nameof(model)); - - var firstShadowEntity = model.GetEntityTypes().FirstOrDefault(entityType => !entityType.HasClrType); - if (firstShadowEntity != null) - { - throw new InvalidOperationException( - CoreStrings.ShadowEntity(firstShadowEntity.DisplayName())); - } } /// @@ -745,8 +740,7 @@ protected virtual void ValidateOwnership( ownership.PrincipalEntityType.DisplayName())); } } - else if (entityType.HasClrType - && ((IMutableModel)model).IsOwned(entityType.ClrType)) + else if (((IMutableModel)model).IsOwned(entityType.ClrType)) { throw new InvalidOperationException(CoreStrings.OwnerlessOwnedType(entityType.DisplayName())); } @@ -1103,8 +1097,7 @@ protected virtual void ValidateData([NotNull] IModel model, [NotNull] IDiagnosti entityType.DisplayName(), key.Properties.Format())); } - entry = new InternalShadowEntityEntry(null, entityType); - + entry = new InternalClrEntityEntry(null, entityType, seedDatum); identityMap.Add(keyValues, entry); } } diff --git a/src/EFCore/Metadata/Builders/EntityTypeBuilder.cs b/src/EFCore/Metadata/Builders/EntityTypeBuilder.cs index 7d656ddda02..3bafd6b7e57 100644 --- a/src/EFCore/Metadata/Builders/EntityTypeBuilder.cs +++ b/src/EFCore/Metadata/Builders/EntityTypeBuilder.cs @@ -824,7 +824,7 @@ public virtual ReferenceNavigationBuilder HasOne([NotNull] string navigationName { Check.NotEmpty(navigationName, nameof(navigationName)); - return Metadata.ClrType == null + return Metadata.ClrType == Model.DefaultPropertyBagType ? HasOne(navigationName, null) // Path only used by pre 3.0 snapshots : HasOne(Metadata.GetNavigationMemberInfo(navigationName).GetMemberType(), navigationName); } diff --git a/src/EFCore/Metadata/Conventions/DerivedTypeDiscoveryConvention.cs b/src/EFCore/Metadata/Conventions/DerivedTypeDiscoveryConvention.cs index 165adcaf53b..bea401fac95 100644 --- a/src/EFCore/Metadata/Conventions/DerivedTypeDiscoveryConvention.cs +++ b/src/EFCore/Metadata/Conventions/DerivedTypeDiscoveryConvention.cs @@ -49,7 +49,6 @@ public virtual void ProcessEntityTypeAdded( foreach (var directlyDerivedType in model.GetEntityTypes()) { if (directlyDerivedType != entityType - && directlyDerivedType.HasClrType && !directlyDerivedType.HasSharedClrType && !directlyDerivedType.HasDefiningNavigation() && !model.IsOwned(directlyDerivedType.ClrType) diff --git a/src/EFCore/Metadata/Conventions/ForeignKeyAttributeConvention.cs b/src/EFCore/Metadata/Conventions/ForeignKeyAttributeConvention.cs index 2bf7b1b8ca4..7ce1579a221 100644 --- a/src/EFCore/Metadata/Conventions/ForeignKeyAttributeConvention.cs +++ b/src/EFCore/Metadata/Conventions/ForeignKeyAttributeConvention.cs @@ -323,8 +323,7 @@ private static TAttribute GetAttribute(MemberInfo memberInfo) [ContractAnnotation("navigationName:null => null")] private MemberInfo FindForeignKeyAttributeOnProperty(IConventionEntityType entityType, string navigationName) { - if (string.IsNullOrWhiteSpace(navigationName) - || !entityType.HasClrType) + if (string.IsNullOrWhiteSpace(navigationName)) { return null; } diff --git a/src/EFCore/Metadata/Conventions/NavigationAttributeConventionBase.cs b/src/EFCore/Metadata/Conventions/NavigationAttributeConventionBase.cs index ad6504a2442..819651a9d7d 100644 --- a/src/EFCore/Metadata/Conventions/NavigationAttributeConventionBase.cs +++ b/src/EFCore/Metadata/Conventions/NavigationAttributeConventionBase.cs @@ -48,13 +48,7 @@ public virtual void ProcessEntityTypeAdded( IConventionEntityTypeBuilder entityTypeBuilder, IConventionContext context) { - var entityType = entityTypeBuilder.Metadata; - if (!entityType.HasClrType) - { - return; - } - - var navigations = GetNavigationsWithAttribute(entityType); + var navigations = GetNavigationsWithAttribute(entityTypeBuilder.Metadata); if (navigations == null) { return; @@ -162,8 +156,7 @@ public virtual void ProcessEntityTypeBaseTypeChanged( IConventionContext context) { var entityType = entityTypeBuilder.Metadata; - if (!entityType.HasClrType - || entityTypeBuilder.Metadata.BaseType != newBaseType) + if (entityTypeBuilder.Metadata.BaseType != newBaseType) { return; } @@ -336,8 +329,7 @@ private static IEnumerable GetAttributes( [NotNull] MemberInfo memberInfo) where TCustomAttribute : Attribute { - if (!entityType.HasClrType - || memberInfo == null) + if (memberInfo == null) { return Enumerable.Empty(); } diff --git a/src/EFCore/Metadata/Conventions/NonNullableNavigationConvention.cs b/src/EFCore/Metadata/Conventions/NonNullableNavigationConvention.cs index d88bd16bca9..6bc1249b3f1 100644 --- a/src/EFCore/Metadata/Conventions/NonNullableNavigationConvention.cs +++ b/src/EFCore/Metadata/Conventions/NonNullableNavigationConvention.cs @@ -81,8 +81,7 @@ private void ProcessNavigation(IConventionNavigationBuilder navigationBuilder) } private bool IsNonNullable(IConventionModelBuilder modelBuilder, IConventionNavigation navigation) - => navigation.DeclaringEntityType.HasClrType - && navigation.DeclaringEntityType.GetRuntimeProperties().Find(navigation.Name) is PropertyInfo propertyInfo + => navigation.DeclaringEntityType.GetRuntimeProperties().Find(navigation.Name) is PropertyInfo propertyInfo && IsNonNullableReferenceType(modelBuilder, propertyInfo); } } diff --git a/src/EFCore/Metadata/Conventions/NotMappedMemberAttributeConvention.cs b/src/EFCore/Metadata/Conventions/NotMappedMemberAttributeConvention.cs index 2b51aef047d..d69e8e20851 100644 --- a/src/EFCore/Metadata/Conventions/NotMappedMemberAttributeConvention.cs +++ b/src/EFCore/Metadata/Conventions/NotMappedMemberAttributeConvention.cs @@ -44,11 +44,6 @@ public virtual void ProcessEntityTypeAdded( Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder)); var entityType = entityTypeBuilder.Metadata; - if (!entityType.HasClrType) - { - return; - } - var members = entityType.GetRuntimeProperties().Values.Cast() .Concat(entityType.GetRuntimeFields().Values); diff --git a/src/EFCore/Metadata/Conventions/OwnedEntityTypeAttributeConvention.cs b/src/EFCore/Metadata/Conventions/OwnedEntityTypeAttributeConvention.cs index 724f7095973..3a53539fc5d 100644 --- a/src/EFCore/Metadata/Conventions/OwnedEntityTypeAttributeConvention.cs +++ b/src/EFCore/Metadata/Conventions/OwnedEntityTypeAttributeConvention.cs @@ -4,7 +4,6 @@ using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Metadata.Builders; using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata.Internal; namespace Microsoft.EntityFrameworkCore.Metadata.Conventions { @@ -33,10 +32,7 @@ protected override void ProcessEntityTypeAdded( OwnedAttribute attribute, IConventionContext context) { - if (entityTypeBuilder.Metadata.HasClrType) - { - entityTypeBuilder.ModelBuilder.Owned(entityTypeBuilder.Metadata.ClrType, fromDataAnnotation: true); - } + entityTypeBuilder.ModelBuilder.Owned(entityTypeBuilder.Metadata.ClrType, fromDataAnnotation: true); } } } diff --git a/src/EFCore/Metadata/Conventions/PropertyDiscoveryConvention.cs b/src/EFCore/Metadata/Conventions/PropertyDiscoveryConvention.cs index a33642d9812..673f525bd58 100644 --- a/src/EFCore/Metadata/Conventions/PropertyDiscoveryConvention.cs +++ b/src/EFCore/Metadata/Conventions/PropertyDiscoveryConvention.cs @@ -63,15 +63,11 @@ public virtual void ProcessEntityTypeBaseTypeChanged( private void Process(IConventionEntityTypeBuilder entityTypeBuilder) { - var entityType = entityTypeBuilder.Metadata; - if (entityType.HasClrType) + foreach (var propertyInfo in entityTypeBuilder.Metadata.GetRuntimeProperties().Values) { - foreach (var propertyInfo in entityType.GetRuntimeProperties().Values) + if (IsCandidatePrimitiveProperty(propertyInfo)) { - if (IsCandidatePrimitiveProperty(propertyInfo)) - { - entityTypeBuilder.Property(propertyInfo); - } + entityTypeBuilder.Property(propertyInfo); } } } diff --git a/src/EFCore/Metadata/Conventions/RelationshipDiscoveryConvention.cs b/src/EFCore/Metadata/Conventions/RelationshipDiscoveryConvention.cs index da712be3209..224db55e53a 100644 --- a/src/EFCore/Metadata/Conventions/RelationshipDiscoveryConvention.cs +++ b/src/EFCore/Metadata/Conventions/RelationshipDiscoveryConvention.cs @@ -45,8 +45,7 @@ public RelationshipDiscoveryConvention([NotNull] ProviderConventionSetBuilderDep private void DiscoverRelationships(IConventionEntityTypeBuilder entityTypeBuilder, IConventionContext context) { - if (!entityTypeBuilder.Metadata.HasClrType - || entityTypeBuilder.ModelBuilder.IsIgnored(entityTypeBuilder.Metadata.ClrType)) + if (entityTypeBuilder.ModelBuilder.IsIgnored(entityTypeBuilder.Metadata.ClrType)) { return; } @@ -982,15 +981,12 @@ private ImmutableSortedDictionary GetNavigationCandidates(IC } var dictionaryBuilder = ImmutableSortedDictionary.CreateBuilder(MemberInfoNameComparer.Instance); - if (entityType.HasClrType) + foreach (var propertyInfo in entityType.GetRuntimeProperties().Values.OrderBy(p => p.Name)) { - foreach (var propertyInfo in entityType.GetRuntimeProperties().Values.OrderBy(p => p.Name)) + var targetType = FindCandidateNavigationPropertyType(propertyInfo); + if (targetType != null) { - var targetType = FindCandidateNavigationPropertyType(propertyInfo); - if (targetType != null) - { - dictionaryBuilder[propertyInfo] = targetType; - } + dictionaryBuilder[propertyInfo] = targetType; } } diff --git a/src/EFCore/Metadata/Conventions/ServicePropertyDiscoveryConvention.cs b/src/EFCore/Metadata/Conventions/ServicePropertyDiscoveryConvention.cs index b348b3b99cb..6b7bb0c08ae 100644 --- a/src/EFCore/Metadata/Conventions/ServicePropertyDiscoveryConvention.cs +++ b/src/EFCore/Metadata/Conventions/ServicePropertyDiscoveryConvention.cs @@ -70,12 +70,6 @@ public virtual void ProcessEntityTypeBaseTypeChanged( private void Process(IConventionEntityTypeBuilder entityTypeBuilder) { var entityType = entityTypeBuilder.Metadata; - - if (!entityType.HasClrType) - { - return; - } - var candidates = entityType.GetRuntimeProperties().Values; foreach (var propertyInfo in candidates) diff --git a/src/EFCore/Metadata/ITypeBase.cs b/src/EFCore/Metadata/ITypeBase.cs index f96629fc363..afb6f56e4b5 100644 --- a/src/EFCore/Metadata/ITypeBase.cs +++ b/src/EFCore/Metadata/ITypeBase.cs @@ -34,14 +34,7 @@ public interface ITypeBase : IAnnotatable /// Therefore, shadow types will only exist in migration model snapshots, etc. /// /// - Type? ClrType { get; } - - /// - /// Gets whether this entity type has an associated CLR type. An entity type without an associated CLR type is known as - /// a shadow type. - /// - [CA.MemberNotNullWhen(true, nameof(ClrType))] - public bool HasClrType => ClrType != null; + Type ClrType { get; } /// /// Gets whether this entity type can share its ClrType with other entities. diff --git a/src/EFCore/Metadata/Internal/EntityType.cs b/src/EFCore/Metadata/Internal/EntityType.cs index 10c11937d3e..8cc801167c1 100644 --- a/src/EFCore/Metadata/Internal/EntityType.cs +++ b/src/EFCore/Metadata/Internal/EntityType.cs @@ -84,7 +84,7 @@ private readonly SortedDictionary _serviceProperties /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public EntityType([NotNull] string name, [NotNull] Model model, ConfigurationSource configurationSource) - : base(name, model, configurationSource) + : base(name, Model.DefaultPropertyBagType, model, configurationSource) { _properties = new SortedDictionary(new PropertyNameComparer(this)); Builder = new InternalEntityTypeBuilder(this, model.Builder); @@ -260,26 +260,12 @@ public virtual void UpdateIsKeylessConfigurationSource(ConfigurationSource confi if (newBaseType != null) { - if (HasClrType) + if (!newBaseType.ClrType.IsAssignableFrom(ClrType)) { - if (!newBaseType.HasClrType) - { - throw new InvalidOperationException(CoreStrings.NonClrBaseType(this.DisplayName(), newBaseType.DisplayName())); - } - - if (!newBaseType.ClrType.IsAssignableFrom(ClrType)) - { - throw new InvalidOperationException( - CoreStrings.NotAssignableClrBaseType( - this.DisplayName(), newBaseType.DisplayName(), ClrType.ShortDisplayName(), - newBaseType.ClrType.ShortDisplayName())); - } - } - - if (!HasClrType - && newBaseType.HasClrType) - { - throw new InvalidOperationException(CoreStrings.NonShadowBaseType(this.DisplayName(), newBaseType.DisplayName())); + throw new InvalidOperationException( + CoreStrings.NotAssignableClrBaseType( + this.DisplayName(), newBaseType.DisplayName(), ClrType.ShortDisplayName(), + newBaseType.ClrType.ShortDisplayName())); } if (newBaseType.InheritsFrom(this)) @@ -1468,8 +1454,7 @@ private Navigation AddNavigation(MemberIdentity navigationMember, ForeignKey for memberInfo = ClrType?.GetMembersInHierarchy(name).FirstOrDefault(); } - if (ClrType != null - && ClrType != Model.DefaultPropertyBagType) + if (memberInfo != null) { Navigation.IsCompatible( name, @@ -1632,7 +1617,7 @@ public virtual IEnumerable GetNavigations() memberInfo = ClrType?.GetMembersInHierarchy(name).FirstOrDefault(); } - if (ClrType != null) + if (memberInfo != null) { Navigation.IsCompatible( name, @@ -1671,11 +1656,6 @@ public virtual IEnumerable GetNavigations() private Type? ValidateClrMember(string name, MemberInfo memberInfo, bool throwOnNameMismatch = true) { - if (ClrType == null) - { - throw new InvalidOperationException(CoreStrings.ClrPropertyOnShadowEntity(memberInfo.Name, this.DisplayName())); - } - if (name != memberInfo.GetSimpleMemberName()) { if (memberInfo != FindIndexerPropertyInfo()) diff --git a/src/EFCore/Metadata/Internal/ForeignKey.cs b/src/EFCore/Metadata/Internal/ForeignKey.cs index 46c3c720314..5e07e77d5b0 100644 --- a/src/EFCore/Metadata/Internal/ForeignKey.cs +++ b/src/EFCore/Metadata/Internal/ForeignKey.cs @@ -530,16 +530,15 @@ public virtual bool IsUnique } if (unique.HasValue - && PrincipalEntityType.HasClrType - && DeclaringEntityType.HasClrType && PrincipalEntityType.ClrType != Model.DefaultPropertyBagType && DeclaringEntityType.ClrType != Model.DefaultPropertyBagType && PrincipalToDependent != null) { if (!Internal.Navigation.IsCompatible( + PrincipalToDependent.Name, PrincipalToDependent.GetIdentifyingMemberInfo(), - PrincipalEntityType.ClrType, - DeclaringEntityType.ClrType, + PrincipalEntityType, + DeclaringEntityType, !unique, shouldThrow: false)) { @@ -1277,9 +1276,10 @@ public static bool AreCompatible( if (navigationToPrincipal != null && !Internal.Navigation.IsCompatible( + navigationToPrincipal.Name, navigationToPrincipal, - dependentEntityType.ClrType!, - principalEntityType.ClrType!, + dependentEntityType, + principalEntityType, shouldBeCollection: false, shouldThrow: shouldThrow)) { @@ -1288,9 +1288,10 @@ public static bool AreCompatible( if (navigationToDependent != null && !Internal.Navigation.IsCompatible( + navigationToDependent.Name, navigationToDependent, - principalEntityType.ClrType!, - dependentEntityType.ClrType!, + principalEntityType, + dependentEntityType, shouldBeCollection: !unique, shouldThrow: shouldThrow)) { diff --git a/src/EFCore/Metadata/Internal/InternalEntityTypeBuilder.cs b/src/EFCore/Metadata/Internal/InternalEntityTypeBuilder.cs index d8b34b535cc..526605b9b49 100644 --- a/src/EFCore/Metadata/Internal/InternalEntityTypeBuilder.cs +++ b/src/EFCore/Metadata/Internal/InternalEntityTypeBuilder.cs @@ -3325,10 +3325,8 @@ public virtual InternalEntityTypeBuilder GetTargetEntityTypeBuilder( "Owned types should only have ownership navigations point at it"); return existingTargetType.HasSharedClrType - ? !existingTargetType.HasClrType - ? ModelBuilder.Entity(existingTargetType.Name, configurationSource.Value, targetShouldBeOwned) - : ModelBuilder.SharedTypeEntity( - existingTargetType.Name, existingTargetType.ClrType, configurationSource.Value, targetShouldBeOwned) + ? ModelBuilder.SharedTypeEntity( + existingTargetType.Name, existingTargetType.ClrType, configurationSource.Value, targetShouldBeOwned) : ModelBuilder.Entity(existingTargetType.ClrType, configurationSource.Value, targetShouldBeOwned); } @@ -3340,8 +3338,7 @@ public virtual InternalEntityTypeBuilder GetTargetEntityTypeBuilder( } } - if (navigation.MemberInfo == null - && Metadata.HasClrType) + if (navigation.MemberInfo == null) { if (Metadata.GetRuntimeProperties().TryGetValue(navigation.Name, out var propertyInfo)) { diff --git a/src/EFCore/Metadata/Internal/InternalForeignKeyBuilder.cs b/src/EFCore/Metadata/Internal/InternalForeignKeyBuilder.cs index 371f217bce9..201bfec0590 100644 --- a/src/EFCore/Metadata/Internal/InternalForeignKeyBuilder.cs +++ b/src/EFCore/Metadata/Internal/InternalForeignKeyBuilder.cs @@ -202,7 +202,6 @@ private InternalForeignKeyBuilder HasNavigations( if (navigationToPrincipalName != null && navigationToPrincipal.Value.MemberInfo == null - && dependentEntityType.HasClrType && dependentEntityType.ClrType != Model.DefaultPropertyBagType) { var navigationProperty = FindCompatibleClrMember( @@ -215,7 +214,6 @@ private InternalForeignKeyBuilder HasNavigations( if (navigationToDependentName != null && navigationToDependent.Value.MemberInfo == null - && principalEntityType.HasClrType && principalEntityType.ClrType != Model.DefaultPropertyBagType) { var navigationProperty = FindCompatibleClrMember( @@ -474,7 +472,7 @@ private static MemberInfo FindCompatibleClrMember( EntityType targetType, bool shouldThrow) { - var navigationProperty = sourceType.FindClrMember(navigationName); + var navigationProperty = sourceType.GetNavigationMemberInfo(navigationName); return !Navigation.IsCompatible(navigationName, navigationProperty, sourceType, targetType, null, shouldThrow) ? null : navigationProperty; @@ -723,8 +721,8 @@ private bool CanSetNavigations( && !IsCompatible( navigationToPrincipalProperty, pointsToPrincipal: false, - principalEntityType.ClrType, - dependentEntityType.ClrType, + principalEntityType, + dependentEntityType, shouldThrow: false, out invertedShouldBeUnique)) { @@ -735,8 +733,8 @@ private bool CanSetNavigations( && !IsCompatible( navigationToDependentProperty, pointsToPrincipal: true, - principalEntityType.ClrType, - dependentEntityType.ClrType, + principalEntityType, + dependentEntityType, shouldThrow: false, out _)) { @@ -749,8 +747,8 @@ private bool CanSetNavigations( && !IsCompatible( navigationToPrincipalProperty, pointsToPrincipal: true, - dependentEntityType.ClrType, - principalEntityType.ClrType, + dependentEntityType, + principalEntityType, shouldThrow && shouldInvert != null, out _)) { @@ -768,8 +766,8 @@ private bool CanSetNavigations( && !IsCompatible( navigationToDependentProperty, pointsToPrincipal: false, - dependentEntityType.ClrType, - principalEntityType.ClrType, + dependentEntityType, + principalEntityType, shouldThrow && shouldInvert != null, out shouldBeUnique)) { @@ -834,8 +832,8 @@ private bool CanSetNavigations( && !IsCompatible( navigationToPrincipalProperty, pointsToPrincipal: true, - Metadata.DeclaringEntityType.ClrType, - Metadata.PrincipalEntityType.ClrType, + Metadata.DeclaringEntityType, + Metadata.PrincipalEntityType, shouldThrow: false, out _)) { @@ -847,8 +845,8 @@ private bool CanSetNavigations( && !IsCompatible( navigationToDependentProperty, pointsToPrincipal: false, - Metadata.DeclaringEntityType.ClrType, - Metadata.PrincipalEntityType.ClrType, + Metadata.DeclaringEntityType, + Metadata.PrincipalEntityType, shouldThrow: false, out _)) { @@ -872,8 +870,8 @@ private bool CanRemoveNavigation(bool pointsToPrincipal, ConfigurationSource? co private static bool IsCompatible( [NotNull] MemberInfo navigationMember, bool pointsToPrincipal, - [NotNull] Type dependentType, - [NotNull] Type principalType, + [NotNull] EntityType dependentType, + [NotNull] EntityType principalType, bool shouldThrow, out bool? shouldBeUnique) { @@ -881,12 +879,14 @@ private static bool IsCompatible( if (!pointsToPrincipal) { var canBeUnique = Navigation.IsCompatible( + navigationMember.Name, navigationMember, principalType, dependentType, shouldBeCollection: false, shouldThrow: false); var canBeNonUnique = Navigation.IsCompatible( + navigationMember.Name, navigationMember, principalType, dependentType, @@ -902,6 +902,7 @@ private static bool IsCompatible( if (shouldThrow) { Navigation.IsCompatible( + navigationMember.Name, navigationMember, principalType, dependentType, @@ -913,6 +914,7 @@ private static bool IsCompatible( } } else if (!Navigation.IsCompatible( + navigationMember.Name, navigationMember, dependentType, principalType, @@ -1307,9 +1309,10 @@ private bool CanSetIsUnique(bool? unique, ConfigurationSource? configurationSour if (Metadata.PrincipalToDependent?.IsShadowProperty() == false && !Navigation.IsCompatible( + Metadata.PrincipalToDependent.Name, Metadata.PrincipalToDependent.GetIdentifyingMemberInfo(), - Metadata.PrincipalEntityType.ClrType, - Metadata.DeclaringEntityType.ClrType, + Metadata.PrincipalEntityType, + Metadata.DeclaringEntityType, !unique, shouldThrow: false)) { @@ -2302,14 +2305,12 @@ private InternalForeignKeyBuilder ReplaceForeignKey( Check.DebugAssert( navigationToPrincipal?.Name == null || navigationToPrincipal.Value.MemberInfo != null - || !dependentEntityTypeBuilder.Metadata.HasClrType || dependentEntityTypeBuilder.Metadata.ClrType == Model.DefaultPropertyBagType, "Principal navigation check failed"); Check.DebugAssert( navigationToDependent?.Name == null || navigationToDependent.Value.MemberInfo != null - || !principalEntityTypeBuilder.Metadata.HasClrType || principalEntityTypeBuilder.Metadata.ClrType == Model.DefaultPropertyBagType, "Dependent navigation check failed"); @@ -3549,8 +3550,7 @@ public virtual InternalForeignKeyBuilder Attach([NotNull] InternalEntityTypeBuil else { if (Metadata.PrincipalEntityType.Name == entityTypeBuilder.Metadata.Name - || (Metadata.PrincipalEntityType.HasClrType - && Metadata.PrincipalEntityType.ClrType == entityTypeBuilder.Metadata.ClrType)) + || Metadata.PrincipalEntityType.ClrType == entityTypeBuilder.Metadata.ClrType) { principalEntityTypeBuilder = entityTypeBuilder; principalEntityType = entityTypeBuilder.Metadata; @@ -3603,8 +3603,7 @@ public virtual InternalForeignKeyBuilder Attach([NotNull] InternalEntityTypeBuil else { if ((Metadata.DeclaringEntityType.Name == entityTypeBuilder.Metadata.Name - || (Metadata.DeclaringEntityType.HasClrType - && Metadata.DeclaringEntityType.ClrType == entityTypeBuilder.Metadata.ClrType)) + || Metadata.DeclaringEntityType.ClrType == entityTypeBuilder.Metadata.ClrType) && (!principalEntityType.HasSharedClrType || principalEntityType != entityTypeBuilder.Metadata)) { @@ -3619,8 +3618,7 @@ public virtual InternalForeignKeyBuilder Attach([NotNull] InternalEntityTypeBuil using (ModelBuilder.Metadata.ConventionDispatcher.DelayConventions()) { if (Metadata.DeclaringEntityType.HasSharedClrType - || (Metadata.DeclaringEntityType.HasClrType - && model.IsShared(Metadata.DeclaringEntityType.ClrType))) + || model.IsShared(Metadata.DeclaringEntityType.ClrType)) { if (Metadata.IsOwnership && Metadata.PrincipalToDependent != null) @@ -3934,8 +3932,8 @@ private bool CanSetRelatedTypes( && !IsCompatible( navigationToPrincipalProperty, !inverted, - inverted ? principalEntityType.ClrType : dependentEntityType.ClrType, - inverted ? dependentEntityType.ClrType : principalEntityType.ClrType, + inverted ? principalEntityType : dependentEntityType, + inverted ? dependentEntityType : principalEntityType, shouldThrow, out invertedShouldBeUnique)) { @@ -3988,8 +3986,8 @@ private bool CanSetRelatedTypes( && !IsCompatible( navigationToDependentProperty, inverted, - inverted ? principalEntityType.ClrType : dependentEntityType.ClrType, - inverted ? dependentEntityType.ClrType : principalEntityType.ClrType, + inverted ? principalEntityType : dependentEntityType, + inverted ? dependentEntityType : principalEntityType, shouldThrow, out toDependentShouldBeUnique)) { diff --git a/src/EFCore/Metadata/Internal/Navigation.cs b/src/EFCore/Metadata/Internal/Navigation.cs index 9847adde32e..6a58a7559b9 100644 --- a/src/EFCore/Metadata/Internal/Navigation.cs +++ b/src/EFCore/Metadata/Internal/Navigation.cs @@ -165,64 +165,24 @@ public virtual void SetIsEagerLoaded(bool? eagerLoaded, ConfigurationSource conf /// public static bool IsCompatible( [NotNull] string navigationName, - [CanBeNull] MemberInfo? navigationProperty, + [NotNull] MemberInfo navigationProperty, [NotNull] EntityType sourceType, [NotNull] EntityType targetType, bool? shouldBeCollection, bool shouldThrow) { - var sourceClrType = sourceType.ClrType; - if (sourceClrType == null) - { - if (shouldThrow) - { - throw new InvalidOperationException(CoreStrings.NavigationFromShadowEntity(navigationName, sourceType.DisplayName())); - } - - return false; - } - - var targetClrType = targetType.ClrType; - if (targetClrType == null) + if (!navigationProperty.DeclaringType!.IsAssignableFrom(sourceType.ClrType)) { if (shouldThrow) { throw new InvalidOperationException( - CoreStrings.NavigationToShadowEntity(navigationName, sourceType.DisplayName(), targetType.DisplayName())); - } - - return false; - } - - return navigationProperty == null - || IsCompatible(navigationProperty, sourceClrType, targetClrType, shouldBeCollection, shouldThrow); - } - - /// - /// 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 bool IsCompatible( - [NotNull] MemberInfo navigationProperty, - [NotNull] Type sourceClrType, - [NotNull] Type targetClrType, - bool? shouldBeCollection, - bool shouldThrow) - { - if (!navigationProperty.DeclaringType!.IsAssignableFrom(sourceClrType)) - { - if (shouldThrow) - { - throw new InvalidOperationException( - CoreStrings.NoClrNavigation( - navigationProperty.Name, sourceClrType.ShortDisplayName())); + CoreStrings.NoClrNavigation(navigationName, sourceType.DisplayName())); } return false; } + var targetClrType = targetType.ClrType; var navigationTargetClrType = navigationProperty.GetMemberType().TryGetSequenceType(); shouldBeCollection ??= navigationTargetClrType != null && navigationProperty.GetMemberType() != targetClrType; if (shouldBeCollection.Value @@ -232,8 +192,8 @@ public static bool IsCompatible( { throw new InvalidOperationException( CoreStrings.NavigationCollectionWrongClrType( - navigationProperty.Name, - sourceClrType.ShortDisplayName(), + navigationName, + sourceType.DisplayName(), navigationProperty.GetMemberType().ShortDisplayName(), targetClrType.ShortDisplayName())); } @@ -248,8 +208,8 @@ public static bool IsCompatible( { throw new InvalidOperationException( CoreStrings.NavigationSingleWrongClrType( - navigationProperty.Name, - sourceClrType.ShortDisplayName(), + navigationName, + sourceType.DisplayName(), navigationProperty.GetMemberType().ShortDisplayName(), targetClrType.ShortDisplayName())); } diff --git a/src/EFCore/Metadata/Internal/Property.cs b/src/EFCore/Metadata/Internal/Property.cs index a6a02419048..0814ec1a94d 100644 --- a/src/EFCore/Metadata/Internal/Property.cs +++ b/src/EFCore/Metadata/Internal/Property.cs @@ -640,11 +640,10 @@ public static bool AreCompatible([NotNull] IReadOnlyList properties, [ return properties.All( property => property.IsShadowProperty() - || (entityType.HasClrType - && ((property.PropertyInfo != null + || ((property.PropertyInfo != null && entityType.GetRuntimeProperties()!.ContainsKey(property.Name)) || (property.FieldInfo != null - && entityType.GetRuntimeFields()!.ContainsKey(property.Name))))); + && entityType.GetRuntimeFields()!.ContainsKey(property.Name)))); } /// diff --git a/src/EFCore/Metadata/Internal/TypeBase.cs b/src/EFCore/Metadata/Internal/TypeBase.cs index f8249d0e264..70f50106ef9 100644 --- a/src/EFCore/Metadata/Internal/TypeBase.cs +++ b/src/EFCore/Metadata/Internal/TypeBase.cs @@ -35,23 +35,6 @@ private readonly Dictionary _ignoredMembers private Dictionary? _runtimeProperties; private Dictionary? _runtimeFields; - /// - /// 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. - /// - protected TypeBase([NotNull] string name, [NotNull] Model model, ConfigurationSource configurationSource) - { - Check.NotEmpty(name, nameof(name)); - Check.NotNull(model, nameof(model)); - - Name = name; - Model = model; - _configurationSource = configurationSource; - _hasSharedClrType = false; - } - /// /// 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 @@ -96,7 +79,7 @@ protected TypeBase([NotNull] string name, [NotNull] Type type, [NotNull] Model m /// 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 Type? ClrType { [DebuggerStepThrough] get; } + public virtual Type ClrType { [DebuggerStepThrough] get; } /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -114,15 +97,6 @@ protected TypeBase([NotNull] string name, [NotNull] Type type, [NotNull] Model m /// public virtual string Name { [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. - /// - [CA.MemberNotNullWhen(true, nameof(ClrType))] - public virtual bool HasClrType => ClrType is not null; - /// /// 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 @@ -405,7 +379,7 @@ IConventionModel IConventionTypeBase.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. /// - Type? ITypeBase.ClrType + Type ITypeBase.ClrType { [DebuggerStepThrough] get => ClrType; } diff --git a/src/EFCore/Metadata/Internal/TypeBaseExtensions.cs b/src/EFCore/Metadata/Internal/TypeBaseExtensions.cs index a5d1c5f9900..5b723b3194c 100644 --- a/src/EFCore/Metadata/Internal/TypeBaseExtensions.cs +++ b/src/EFCore/Metadata/Internal/TypeBaseExtensions.cs @@ -44,17 +44,6 @@ public static IReadOnlyDictionary GetRuntimeFields([NotNull] public static PropertyInfo FindIndexerPropertyInfo([NotNull] this ITypeBase type) => (type as TypeBase).FindIndexerPropertyInfo(); - /// - /// 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 MemberInfo FindClrMember([NotNull] this TypeBase type, [NotNull] string name) - => type.GetRuntimeProperties().TryGetValue(name, out var property) - ? property - : (MemberInfo)(type.GetRuntimeFields().TryGetValue(name, out var field) ? field : null); - /// /// 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 diff --git a/src/EFCore/Properties/CoreStrings.Designer.cs b/src/EFCore/Properties/CoreStrings.Designer.cs index bd3fa19bf18..332181285db 100644 --- a/src/EFCore/Properties/CoreStrings.Designer.cs +++ b/src/EFCore/Properties/CoreStrings.Designer.cs @@ -388,6 +388,7 @@ public static string ClientProjectionCapturingConstantInTree([CanBeNull] object? /// /// The property '{property}' cannot exist on type '{entityType}' because the type is marked as shadow state while the property is not. Shadow state types can only contain shadow state properties. /// + [Obsolete] public static string ClrPropertyOnShadowEntity([CanBeNull] object? property, [CanBeNull] object? entityType) => string.Format( GetString("ClrPropertyOnShadowEntity", nameof(property), nameof(entityType)), @@ -1604,6 +1605,7 @@ public static string NavigationForWrongForeignKey([CanBeNull] object? navigation /// /// The navigation '{navigation}' cannot be added to the entity type '{entityType}' because it is defined in shadow state, and navigations properties cannot originate from shadow state entities. /// + [Obsolete] public static string NavigationFromShadowEntity([CanBeNull] object? navigation, [CanBeNull] object? entityType) => string.Format( GetString("NavigationFromShadowEntity", nameof(navigation), nameof(entityType)), @@ -1652,6 +1654,7 @@ public static string NavigationToKeylessType([CanBeNull] object? navigation, [Ca /// /// The navigation '{navigation}' cannot be added to the entity type '{entityType}' because the target entity type '{targetType}' is defined in shadow state, and navigations properties cannot point to shadow state entities. /// + [Obsolete] public static string NavigationToShadowEntity([CanBeNull] object? navigation, [CanBeNull] object? entityType, [CanBeNull] object? targetType) => string.Format( GetString("NavigationToShadowEntity", nameof(navigation), nameof(entityType), nameof(targetType)), @@ -1762,6 +1765,7 @@ public static string NoNavigation([CanBeNull] object? entityType, [CanBeNull] ob /// /// The entity type '{entityType}' cannot inherit from '{baseEntityType}' because '{baseEntityType}' is a shadow state entity type while '{entityType}' is not. /// + [Obsolete] public static string NonClrBaseType([CanBeNull] object? entityType, [CanBeNull] object? baseEntityType) => string.Format( GetString("NonClrBaseType", nameof(entityType), nameof(baseEntityType)), @@ -1827,6 +1831,7 @@ public static string NonNotifyingCollection([CanBeNull] object? navigation, [Can /// /// The entity type '{entityType}' cannot inherit from '{baseEntityType}' because '{entityType}' is a shadow state entity type while '{baseEntityType}' is not. /// + [Obsolete] public static string NonShadowBaseType([CanBeNull] object? entityType, [CanBeNull] object? baseEntityType) => string.Format( GetString("NonShadowBaseType", nameof(entityType), nameof(baseEntityType)), @@ -2435,6 +2440,7 @@ public static string SetOperationWithDifferentIncludesInOperands /// /// The entity type '{entityType}' is in shadow state. A valid model requires all entity types to have a corresponding CLR type. /// + [Obsolete] public static string ShadowEntity([CanBeNull] object? entityType) => string.Format( GetString("ShadowEntity", nameof(entityType)), diff --git a/src/EFCore/Properties/CoreStrings.resx b/src/EFCore/Properties/CoreStrings.resx index d6b2c6b2500..a6eaf0a1b04 100644 --- a/src/EFCore/Properties/CoreStrings.resx +++ b/src/EFCore/Properties/CoreStrings.resx @@ -257,6 +257,7 @@ The property '{property}' cannot exist on type '{entityType}' because the type is marked as shadow state while the property is not. Shadow state types can only contain shadow state properties. + Obsolete The property '{1_entityType}.{0_property}' is being accessed using '{collectionMethod}', but is defined in the model as a non-collection, reference navigation. Use '{referenceMethod}' to access reference navigations. @@ -1023,6 +1024,7 @@ The navigation '{navigation}' cannot be added to the entity type '{entityType}' because it is defined in shadow state, and navigations properties cannot originate from shadow state entities. + Obsolete The property '{1_entityType}.{0_property}' is being accessed using the '{referenceMethod}' or '{collectionMethod}' method, but is defined in the model as a non-navigation. Use the '{propertyMethod}' method to access non-navigation properties. @@ -1041,6 +1043,7 @@ The navigation '{navigation}' cannot be added to the entity type '{entityType}' because the target entity type '{targetType}' is defined in shadow state, and navigations properties cannot point to shadow state entities. + Obsolete No backing field was found for property '{1_entityType}.{0_property}'. Name the backing field so that it is discovered by convention, configure the backing field to use, or use a different '{propertyAccessMode}'. @@ -1085,6 +1088,7 @@ The entity type '{entityType}' cannot inherit from '{baseEntityType}' because '{baseEntityType}' is a shadow state entity type while '{entityType}' is not. + Obsolete Property '{entityType}.{property}' cannot be used as a key because it has type '{providerType}' which does not implement 'IComparable<T>', 'IComparable' or 'IStructuralComparable'. Use 'HasConversion' in 'OnModelCreating' to wrap '{providerType}' with a type that can be compared. @@ -1110,6 +1114,7 @@ The entity type '{entityType}' cannot inherit from '{baseEntityType}' because '{entityType}' is a shadow state entity type while '{baseEntityType}' is not. + Obsolete The foreign key {foreignKeyProperties} on the entity type '{declaringEntityType}' cannot have a required dependent end since it is not unique. @@ -1350,6 +1355,7 @@ The entity type '{entityType}' is in shadow state. A valid model requires all entity types to have a corresponding CLR type. + Obsolete The shared-type entity type '{entityType}' cannot have a base type. diff --git a/src/EFCore/Query/Internal/EntityMaterializerSource.cs b/src/EFCore/Query/Internal/EntityMaterializerSource.cs index 78732b0f7b4..1d7edf2a337 100644 --- a/src/EFCore/Query/Internal/EntityMaterializerSource.cs +++ b/src/EFCore/Query/Internal/EntityMaterializerSource.cs @@ -59,8 +59,6 @@ public virtual Expression CreateMaterializeExpression( string entityInstanceName, Expression materializationContextExpression) { - Check.DebugAssert(entityType.HasClrType, "Cannot materialize shadow types."); - if (entityType.IsAbstract()) { throw new InvalidOperationException(CoreStrings.CannotMaterializeAbstractType(entityType.DisplayName())); diff --git a/src/Shared/DictionaryExtensions.cs b/src/Shared/DictionaryExtensions.cs index c88bd4a1c08..05e19f0debe 100644 --- a/src/Shared/DictionaryExtensions.cs +++ b/src/Shared/DictionaryExtensions.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.Diagnostics; using JetBrains.Annotations; @@ -28,5 +29,61 @@ public static TValue Find( [NotNull] this IReadOnlyDictionary source, [NotNull] TKey key) => !source.TryGetValue(key, out var value) ? default : value; + + public static void Remove( + [NotNull] this IDictionary source, + [NotNull] Func predicate) + => source.Remove((k, v, p) => p(k, v), predicate); + + public static void Remove( + [NotNull] this IDictionary source, + [NotNull] Func predicate, + [CanBeNull] TState state) + { + var found = false; + var firstRemovedKey = default(TKey); + List> pairsRemainder = null; + foreach (var pair in source) + { + if (found) + { + if (pairsRemainder == null) + { + pairsRemainder = new List>(); + } + + pairsRemainder.Add(pair); + continue; + } + + if (!predicate(pair.Key, pair.Value, state)) + { + continue; + } + + if (!found) + { + found = true; + firstRemovedKey = pair.Key; + } + } + + if (found) + { + source.Remove(firstRemovedKey); + if (pairsRemainder == null) + { + return; + } + + foreach (var pair in pairsRemainder) + { + if (predicate(pair.Key, pair.Value, state)) + { + source.Remove(pair.Key); + } + } + } + } } } diff --git a/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.cs b/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.cs index 9c15f4aaef6..44a8cd802a0 100644 --- a/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.cs +++ b/test/EFCore.Design.Tests/Migrations/Design/CSharpMigrationsGeneratorTest.cs @@ -775,7 +775,7 @@ public void Snapshot_with_default_values_are_round_tripped() var snapshot = CompileModelSnapshot(modelSnapshotCode, "MyNamespace.MySnapshot"); var entityType = snapshot.Model.GetEntityTypes().Single(); - Assert.Equal(typeof(EntityWithEveryPrimitive).FullName, entityType.DisplayName()); + Assert.Equal(typeof(EntityWithEveryPrimitive).FullName + " (Dictionary)", entityType.DisplayName()); foreach (var property in modelBuilder.Model.GetEntityTypes().Single().GetProperties()) { diff --git a/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs b/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs index 2ca9b4092a4..5b49e09d5a8 100644 --- a/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs +++ b/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs @@ -1292,18 +1292,18 @@ public virtual void Many_to_many_join_table_stored_in_snapshot() model => { var joinEntity = model.FindEntityType("ManyToManyLeftManyToManyRight"); - Assert.NotNull(joinEntity); + Assert.Equal(typeof(Dictionary), joinEntity.ClrType); Assert.Collection( joinEntity.GetDeclaredProperties(), p => { Assert.Equal("LeftsId", p.Name); - Assert.True(p.IsShadowProperty()); + Assert.False(p.IsShadowProperty()); }, p => { Assert.Equal("RightsId", p.Name); - Assert.True(p.IsShadowProperty()); + Assert.False(p.IsShadowProperty()); }); Assert.Collection( joinEntity.FindDeclaredPrimaryKey().Properties, @@ -1433,19 +1433,19 @@ public virtual void Can_override_table_name_for_many_to_many_join_table_stored_i model => { var joinEntity = model.FindEntityType("ManyToManyLeftManyToManyRight"); - Assert.NotNull(joinEntity); + Assert.Equal(typeof(Dictionary), joinEntity.ClrType); Assert.Equal("MyJoinTable", joinEntity.GetTableName()); Assert.Collection( joinEntity.GetDeclaredProperties(), p => { Assert.Equal("LeftsId", p.Name); - Assert.True(p.IsShadowProperty()); + Assert.False(p.IsShadowProperty()); }, p => { Assert.Equal("RightsId", p.Name); - Assert.True(p.IsShadowProperty()); + Assert.False(p.IsShadowProperty()); }); Assert.Collection( joinEntity.FindDeclaredPrimaryKey().Properties, diff --git a/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpModelGeneratorTest.cs b/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpModelGeneratorTest.cs index 25b89dd5eca..77fa2699b2d 100644 --- a/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpModelGeneratorTest.cs +++ b/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpModelGeneratorTest.cs @@ -30,8 +30,11 @@ public void WriteCode_works() var modelBuilder = RelationalTestHelpers.Instance.CreateConventionBuilder(); modelBuilder.Entity("TestEntity").Property("Id").HasAnnotation(ScaffoldingAnnotationNames.ColumnOrdinal, 0); + var model = (Model)modelBuilder.Model; + var finalizedModel = model.ConventionDispatcher.OnModelFinalizing(model.Builder)?.Metadata; + var result = generator.GenerateModel( - modelBuilder.Model, + finalizedModel, new ModelCodeGenerationOptions { ModelNamespace = "TestNamespace", diff --git a/test/EFCore.Relational.Tests/Migrations/Internal/MigrationsModelDifferTest.cs b/test/EFCore.Relational.Tests/Migrations/Internal/MigrationsModelDifferTest.cs index 26b79b5a8e1..67f69751e40 100644 --- a/test/EFCore.Relational.Tests/Migrations/Internal/MigrationsModelDifferTest.cs +++ b/test/EFCore.Relational.Tests/Migrations/Internal/MigrationsModelDifferTest.cs @@ -6598,25 +6598,25 @@ public void Change_TPH_to_TPT_with_FKs_and_seed_data_readonly_discriminator() { var operation = Assert.IsType(o); Assert.Equal("Animal", operation.Table); - Assert.Equal(new[] { "Id", "Discriminator", "MouseId" }, operation.Columns); + Assert.Equal(new[] { "Id", "Discriminator", "MouseId", "PreyId" }, operation.Columns); Assert.Null(operation.ColumnTypes); AssertMultidimensionalArray( operation.Values, - v => Assert.Equal(31, v), - v => Assert.Equal("Mouse", v), + v => Assert.Equal(13, v), + v => Assert.Equal("Cat", v), + v => Assert.Null(v), v => Assert.Null(v)); }, o => { var operation = Assert.IsType(o); Assert.Equal("Animal", operation.Table); - Assert.Equal(new[] { "Id", "Discriminator", "MouseId", "PreyId" }, operation.Columns); + Assert.Equal(new[] { "Id", "Discriminator", "MouseId" }, operation.Columns); Assert.Null(operation.ColumnTypes); AssertMultidimensionalArray( operation.Values, - v => Assert.Equal(13, v), - v => Assert.Equal("Cat", v), - v => Assert.Null(v), + v => Assert.Equal(31, v), + v => Assert.Equal("Mouse", v), v => Assert.Null(v)); }, o => @@ -6638,10 +6638,10 @@ public void Change_TPH_to_TPT_with_FKs_and_seed_data_readonly_discriminator() Assert.Null(operation.ColumnTypes); AssertMultidimensionalArray( operation.Values, - v => Assert.Equal(21, v), - v => Assert.Equal("Dog", v), - v => Assert.Null(v), - v => Assert.Equal(31, v)); + v => Assert.Equal(11, v), + v => Assert.Equal("Cat", v), + v => Assert.Equal(31, v), + v => Assert.Null(v)); }, o => { @@ -6651,9 +6651,9 @@ public void Change_TPH_to_TPT_with_FKs_and_seed_data_readonly_discriminator() Assert.Null(operation.ColumnTypes); AssertMultidimensionalArray( operation.Values, - v => Assert.Equal(11, v), + v => Assert.Equal(12, v), v => Assert.Equal("Cat", v), - v => Assert.Equal(31, v), + v => Assert.Equal(32, v), v => Assert.Null(v)); }, o => @@ -6664,10 +6664,10 @@ public void Change_TPH_to_TPT_with_FKs_and_seed_data_readonly_discriminator() Assert.Null(operation.ColumnTypes); AssertMultidimensionalArray( operation.Values, - v => Assert.Equal(22, v), + v => Assert.Equal(21, v), v => Assert.Equal("Dog", v), v => Assert.Null(v), - v => Assert.Equal(32, v)); + v => Assert.Equal(31, v)); }, o => { @@ -6677,10 +6677,10 @@ public void Change_TPH_to_TPT_with_FKs_and_seed_data_readonly_discriminator() Assert.Null(operation.ColumnTypes); AssertMultidimensionalArray( operation.Values, - v => Assert.Equal(12, v), - v => Assert.Equal("Cat", v), - v => Assert.Equal(32, v), - v => Assert.Null(v)); + v => Assert.Equal(22, v), + v => Assert.Equal("Dog", v), + v => Assert.Null(v), + v => Assert.Equal(32, v)); }, o => { diff --git a/test/EFCore.Specification.Tests/OptimisticConcurrencyTestBase.cs b/test/EFCore.Specification.Tests/OptimisticConcurrencyTestBase.cs index 470d9ca4e31..f26db3bd871 100644 --- a/test/EFCore.Specification.Tests/OptimisticConcurrencyTestBase.cs +++ b/test/EFCore.Specification.Tests/OptimisticConcurrencyTestBase.cs @@ -34,7 +34,7 @@ public virtual void External_model_builder_uses_validation() modelBuilder.Entity("Dummy"); Assert.Equal( - CoreStrings.ShadowEntity("Dummy"), + CoreStrings.EntityRequiresKey("Dummy (Dictionary)"), Assert.Throws (() => modelBuilder.FinalizeModel()).Message); } diff --git a/test/EFCore.SqlServer.Tests/SqlServerTypeMapperTest.cs b/test/EFCore.SqlServer.Tests/SqlServerTypeMapperTest.cs index e7aa767221f..dba574ac350 100644 --- a/test/EFCore.SqlServer.Tests/SqlServerTypeMapperTest.cs +++ b/test/EFCore.SqlServer.Tests/SqlServerTypeMapperTest.cs @@ -1011,7 +1011,7 @@ public void Throws_for_unrecognized_property_types() var property = ((IMutableModel)new Model()).AddEntityType("Entity1") .AddProperty("Strange", typeof(object)); var ex = Assert.Throws(() => CreateTypeMapper().GetMapping(property)); - Assert.Equal(RelationalStrings.UnsupportedPropertyType("Entity1", "Strange", "object"), ex.Message); + Assert.Equal(RelationalStrings.UnsupportedPropertyType("Entity1 (Dictionary)", "Strange", "object"), ex.Message); Assert.Equal(RelationalStrings.UnsupportedType("object"), Assert.Throws(() => CreateTypeMapper().GetMapping(typeof(object))).Message); diff --git a/test/EFCore.Tests/ChangeTracking/Internal/InternalEntityEntryFactoryTest.cs b/test/EFCore.Tests/ChangeTracking/Internal/InternalEntityEntryFactoryTest.cs index 980c5b77abc..9edd1834342 100644 --- a/test/EFCore.Tests/ChangeTracking/Internal/InternalEntityEntryFactoryTest.cs +++ b/test/EFCore.Tests/ChangeTracking/Internal/InternalEntityEntryFactoryTest.cs @@ -13,28 +13,6 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal { public class InternalEntityEntryFactoryTest { - [ConditionalFact] - public void Creates_shadow_state_only_entry_when_entity_is_fully_shadow_state() - { - var model = CreateModel(); - var entityType = model.AddEntityType("RedHook"); - entityType.AddProperty("Long", typeof(int)); - entityType.AddProperty("Hammer", typeof(string)); - model.FinalizeModel(); - - var contextServices = InMemoryTestHelpers.Instance.CreateContextServices(model); - var stateManager = contextServices.GetRequiredService(); - var factory = contextServices.GetRequiredService(); - - var entry = factory.Create(stateManager, entityType, new Random()); - - Assert.IsType(entry); - - Assert.Same(stateManager, entry.StateManager); - Assert.Same(entityType, entry.EntityType); - Assert.Null(entry.Entity); - } - [ConditionalFact] public void Creates_CLR_only_entry_when_entity_has_no_shadow_properties() { diff --git a/test/EFCore.Tests/Extensions/PropertyExtensionsTest.cs b/test/EFCore.Tests/Extensions/PropertyExtensionsTest.cs index a14fc16d266..76fe1457398 100644 --- a/test/EFCore.Tests/Extensions/PropertyExtensionsTest.cs +++ b/test/EFCore.Tests/Extensions/PropertyExtensionsTest.cs @@ -80,7 +80,7 @@ public virtual void Value_converter_type_is_checked() property2.SetValueConverter(new CastingConverter()); Assert.Equal( - CoreStrings.ConverterPropertyMismatch("long", "Entity", "Property1", "int"), + CoreStrings.ConverterPropertyMismatch("long", "Entity (Dictionary)", "Property1", "int"), Assert.Throws( () => property1.SetValueConverter(new CastingConverter())).Message); } diff --git a/test/EFCore.Tests/Infrastructure/ModelValidatorTest.cs b/test/EFCore.Tests/Infrastructure/ModelValidatorTest.cs index ddf7a0b8ad6..12d922e842a 100644 --- a/test/EFCore.Tests/Infrastructure/ModelValidatorTest.cs +++ b/test/EFCore.Tests/Infrastructure/ModelValidatorTest.cs @@ -189,16 +189,6 @@ public virtual void Detects_filter_on_owned_type() VerifyError(CoreStrings.BadFilterOwnedType(queryFilter, nameof(ReferencedEntity)), modelBuilder.Model); } - [ConditionalFact] - public virtual void Detects_shadow_entities() - { - var model = CreateConventionlessModelBuilder().Model; - var entityType = model.AddEntityType("BewareTheShadows"); - SetPrimaryKey(entityType); - - VerifyError(CoreStrings.ShadowEntity("BewareTheShadows"), model); - } - [ConditionalFact] public virtual void Passes_on_shadow_key_created_explicitly() { diff --git a/test/EFCore.Tests/Metadata/Conventions/PropertyMappingValidationConventionTest.cs b/test/EFCore.Tests/Metadata/Conventions/PropertyMappingValidationConventionTest.cs index a02c64d7ac6..f3db8483703 100644 --- a/test/EFCore.Tests/Metadata/Conventions/PropertyMappingValidationConventionTest.cs +++ b/test/EFCore.Tests/Metadata/Conventions/PropertyMappingValidationConventionTest.cs @@ -6,13 +6,16 @@ using System.Linq; using System.Reflection; using System.Threading; +using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.InMemory.Storage.Internal; using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata.Internal; +using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.TestUtilities; +using Microsoft.EntityFrameworkCore.Update; using Microsoft.Extensions.DependencyInjection; using Xunit; diff --git a/test/EFCore.Tests/Metadata/Internal/EntityTypeTest.BaseType.cs b/test/EFCore.Tests/Metadata/Internal/EntityTypeTest.BaseType.cs index 70d4708fae3..6f3fdbb7201 100644 --- a/test/EFCore.Tests/Metadata/Internal/EntityTypeTest.BaseType.cs +++ b/test/EFCore.Tests/Metadata/Internal/EntityTypeTest.BaseType.cs @@ -67,7 +67,8 @@ public void Setting_CLR_base_for_shadow_entity_type_should_throw() var b = model.AddEntityType(typeof(B).Name); Assert.Equal( - CoreStrings.NonShadowBaseType(typeof(B).Name, typeof(A).Name), + CoreStrings.NotAssignableClrBaseType( + typeof(B).Name + " (Dictionary)", typeof(A).Name, "Dictionary", typeof(A).Name), Assert.Throws(() => b.BaseType = a).Message); } @@ -80,7 +81,8 @@ public void Setting_shadow_base_for_CLR_entity_type_should_throw() var b = model.AddEntityType(typeof(B)); Assert.Equal( - CoreStrings.NonClrBaseType(typeof(B).Name, typeof(A).Name), + CoreStrings.NotAssignableClrBaseType( + typeof(B).Name, typeof(A).Name + " (Dictionary)", typeof(B).Name, "Dictionary"), Assert.Throws(() => b.BaseType = a).Message); } diff --git a/test/EFCore.Tests/Metadata/Internal/EntityTypeTest.cs b/test/EFCore.Tests/Metadata/Internal/EntityTypeTest.cs index ec11734742c..baf6d9f6e11 100644 --- a/test/EFCore.Tests/Metadata/Internal/EntityTypeTest.cs +++ b/test/EFCore.Tests/Metadata/Internal/EntityTypeTest.cs @@ -134,7 +134,7 @@ public void Display_name_is_prettified_CLR_name() [ConditionalFact] public void Display_name_is_entity_type_name_when_no_CLR_type() => Assert.Equal( - "Everything.Is+Awesome>", + "Everything.Is+Awesome> (Dictionary)", CreateModel().AddEntityType("Everything.Is+Awesome>").DisplayName()); [ConditionalFact] @@ -1069,7 +1069,8 @@ public void Adding_a_navigation_on_non_shadow_entity_type_pointing_to_a_shadow_e var customerForeignKey = orderType.AddForeignKey(foreignKeyProperty, customerKey, customerType); Assert.Equal( - CoreStrings.NavigationToShadowEntity(nameof(Order.Customer), typeof(Order).Name, "Customer"), + CoreStrings.NavigationSingleWrongClrType( + nameof(Order.Customer), typeof(Order).Name, "Customer", "Dictionary"), Assert.Throws( () => customerForeignKey.SetDependentToPrincipal(Order.CustomerProperty)).Message); } @@ -1396,26 +1397,6 @@ public void Adding_skip_navigation_with_a_name_that_conflicts_with_a_service_pro nameof(Order.Products), null, productEntity, true, false)).Message); } - [ConditionalFact] - public void Adding_CLR_skip_navigation_to_shadow_entity_type_throws() - { - var model = CreateModel(); - var orderEntity = model.AddEntityType(nameof(Order)); - var orderIdProperty = orderEntity.AddProperty(nameof(Order.Id), typeof(int)); - var orderKey = orderEntity.AddKey(orderIdProperty); - var productEntity = model.AddEntityType(nameof(Product)); - var orderProductEntity = model.AddEntityType(nameof(OrderProduct)); - var orderProductFkProperty = orderProductEntity.AddProperty(nameof(OrderProduct.OrderId), typeof(int)); - var orderProductForeignKey = orderProductEntity - .AddForeignKey(new[] { orderProductFkProperty }, orderKey, orderEntity); - - Assert.Equal( - CoreStrings.ClrPropertyOnShadowEntity(nameof(Order.Products), nameof(Order)), - Assert.Throws( - () => orderEntity.AddSkipNavigation( - nameof(Order.Products), Order.ProductsProperty, productEntity, true, false)).Message); - } - [ConditionalFact] public void Adding_CLR_skip_navigation_targetting_a_shadow_entity_type_throws() { @@ -1430,7 +1411,8 @@ public void Adding_CLR_skip_navigation_targetting_a_shadow_entity_type_throws() .AddForeignKey(new[] { orderProductFkProperty }, orderKey, orderEntity); Assert.Equal( - CoreStrings.NavigationToShadowEntity(nameof(Order.Products), nameof(Order), nameof(Product)), + CoreStrings.NavigationCollectionWrongClrType( + nameof(Order.Products), nameof(Order), "ICollection", "Dictionary"), Assert.Throws( () => orderEntity.AddSkipNavigation( nameof(Order.Products), Order.ProductsProperty, productEntity, true, false)).Message); @@ -1822,17 +1804,6 @@ public void AddProperty_throws_for_wrong_entity_type() () => entityType.AddProperty(Customer.NameProperty)).Message); } - [ConditionalFact] - public void AddProperty_throws_if_shadow_entity_type() - { - var entityType = CreateModel().AddEntityType("Customer"); - - Assert.Equal( - CoreStrings.ClrPropertyOnShadowEntity(nameof(Customer.Name), "Customer"), - Assert.Throws( - () => entityType.AddProperty(Customer.NameProperty)).Message); - } - [ConditionalFact] public void AddProperty_throws_if_no_clr_property_or_field() { @@ -2164,17 +2135,6 @@ public void Adding_a_new_service_property_with_a_type_that_already_exists_throws Assert.Throws(() => entityType.AddServiceProperty(Customer.MoreOrdersProperty)).Message); } - [ConditionalFact] - public void Adding_a_CLR_service_property_to_shadow_type_throws() - { - var model = CreateModel(); - var entityType = model.AddEntityType(typeof(Customer).Name); - - Assert.Equal( - CoreStrings.ClrPropertyOnShadowEntity(Order.CustomerIdProperty.Name, typeof(Customer).Name), - Assert.Throws(() => entityType.AddServiceProperty(Order.CustomerIdProperty)).Message); - } - [ConditionalFact] public void Can_add_indexed_property() { diff --git a/test/EFCore.Tests/Metadata/Internal/ForeignKeyTest.cs b/test/EFCore.Tests/Metadata/Internal/ForeignKeyTest.cs index 4cebcad8929..c60eaf7ccbe 100644 --- a/test/EFCore.Tests/Metadata/Internal/ForeignKeyTest.cs +++ b/test/EFCore.Tests/Metadata/Internal/ForeignKeyTest.cs @@ -83,7 +83,7 @@ public void Constructor_throws_when_referenced_key_not_on_referenced_entity() var principalKey = dependentEntityType.SetPrimaryKey(fk); Assert.Equal( - CoreStrings.ForeignKeyReferencedEntityKeyMismatch("{'Fk'}", "R"), + CoreStrings.ForeignKeyReferencedEntityKeyMismatch("{'Fk'}", "R (Dictionary)"), Assert.Throws( () => dependentEntityType.AddForeignKey(new[] { fk }, principalKey, principalEntityType)).Message); } @@ -102,7 +102,7 @@ public void Constructor_throws_when_principal_and_dependent_property_count_do_no principalEntityType.SetPrimaryKey(idProperty); Assert.Equal( - CoreStrings.ForeignKeyCountMismatch("{'P1', 'P2'}", "D", "{'Id'}", "P"), + CoreStrings.ForeignKeyCountMismatch("{'P1', 'P2'}", "D (Dictionary)", "{'Id'}", "P (Dictionary)"), Assert.Throws( () => dependentEntityType.AddForeignKey( new[] { dependentProperty1, dependentProperty2 }, principalEntityType.FindPrimaryKey(), principalEntityType)) @@ -124,7 +124,7 @@ public void Constructor_throws_when_principal_and_dependent_property_types_do_no new[] { property2, property3 }); Assert.Equal( - CoreStrings.ForeignKeyTypeMismatch("{'P1' : int, 'P2' : string}", "D", "{'Id1' : int, 'Id2' : int}", "P"), + CoreStrings.ForeignKeyTypeMismatch("{'P1' : int, 'P2' : string}", "D (Dictionary)", "{'Id1' : int, 'Id2' : int}", "P (Dictionary)"), Assert.Throws( () => dependentEntityType.AddForeignKey( new[] { dependentProperty1, dependentProperty2 }, principalEntityType.FindPrimaryKey(), principalEntityType)) diff --git a/test/EFCore.Tests/Metadata/Internal/InternalEntityTypeBuilderTest.cs b/test/EFCore.Tests/Metadata/Internal/InternalEntityTypeBuilderTest.cs index 93cc80a178a..13fdba88774 100644 --- a/test/EFCore.Tests/Metadata/Internal/InternalEntityTypeBuilderTest.cs +++ b/test/EFCore.Tests/Metadata/Internal/InternalEntityTypeBuilderTest.cs @@ -1109,16 +1109,15 @@ public void Key_throws_for_derived_type_before_HasBase() } [ConditionalFact] - public void Key_throws_for_property_names_for_shadow_entity_type_if_they_do_not_exist() + public void Key_throws_for_property_names_for_shared_entity_type_if_they_do_not_exist() { var modelBuilder = CreateModelBuilder(); var entityBuilder = modelBuilder.Entity(typeof(Order).Name, ConfigurationSource.Explicit); Assert.Equal( - CoreStrings.NoPropertyType(Order.IdProperty.Name, nameof(Order)), + CoreStrings.NoPropertyType(Order.IdProperty.Name, nameof(Order) + " (Dictionary)"), Assert.Throws( - () => - entityBuilder.HasKey(new[] { Order.IdProperty.Name }, ConfigurationSource.Convention)).Message); + () => entityBuilder.HasKey(new[] { Order.IdProperty.Name }, ConfigurationSource.Convention)).Message); } [ConditionalFact] @@ -1353,21 +1352,19 @@ public void PrimaryKey_throws_for_property_names_if_they_do_not_exist() Assert.Equal( CoreStrings.NoPropertyType(Customer.UniqueProperty.Name, nameof(Order)), Assert.Throws( - () => - entityBuilder.PrimaryKey(new[] { Customer.UniqueProperty.Name }, ConfigurationSource.Convention)).Message); + () => entityBuilder.PrimaryKey(new[] { Customer.UniqueProperty.Name }, ConfigurationSource.Convention)).Message); } [ConditionalFact] - public void PrimaryKey_throws_for_property_names_for_shadow_entity_type_if_they_do_not_exist() + public void PrimaryKey_throws_for_property_names_for_shared_entity_type_if_they_do_not_exist() { var modelBuilder = CreateModelBuilder(); var entityBuilder = modelBuilder.Entity(typeof(Order).Name, ConfigurationSource.Explicit); Assert.Equal( - CoreStrings.NoPropertyType(Order.IdProperty.Name, nameof(Order)), + CoreStrings.NoPropertyType(Order.IdProperty.Name, nameof(Order) + " (Dictionary)"), Assert.Throws( - () => - entityBuilder.PrimaryKey(new[] { Order.IdProperty.Name }, ConfigurationSource.Convention)).Message); + () => entityBuilder.PrimaryKey(new[] { Order.IdProperty.Name }, ConfigurationSource.Convention)).Message); } [ConditionalFact] @@ -3256,7 +3253,7 @@ public void DiscriminatorValue_throws_if_base_cannot_be_set() var discriminatorBuilder = typeBuilder.HasDiscriminator(); Assert.Equal( - CoreStrings.DiscriminatorEntityTypeNotDerived("Splow", "Splot"), + CoreStrings.DiscriminatorEntityTypeNotDerived("Splow (Dictionary)", "Splot (Dictionary)"), Assert.Throws( () => discriminatorBuilder.HasValue(nonDerivedTypeBuilder.Metadata, "1")).Message); } diff --git a/test/EFCore.Tests/Metadata/Internal/ModelTest.cs b/test/EFCore.Tests/Metadata/Internal/ModelTest.cs index 401964a3047..1b2df774d25 100644 --- a/test/EFCore.Tests/Metadata/Internal/ModelTest.cs +++ b/test/EFCore.Tests/Metadata/Internal/ModelTest.cs @@ -97,7 +97,7 @@ public void Can_add_and_remove_entity_by_name() var entityType = model.AddEntityType(typeof(Customer).FullName); - Assert.Null(entityType.ClrType); + Assert.Equal(typeof(Dictionary), entityType.ClrType); Assert.Equal(typeof(Customer).FullName, entityType.Name); Assert.NotNull(model.FindEntityType(typeof(Customer).FullName)); Assert.Same(model, entityType.Model); @@ -218,7 +218,7 @@ public void Adding_duplicate_entity_by_name_throws() model.AddEntityType(typeof(Customer)); Assert.Equal( - CoreStrings.DuplicateEntityType(typeof(Customer).FullName), + CoreStrings.DuplicateEntityType(typeof(Customer).FullName + " (Dictionary)"), Assert.Throws(() => model.AddEntityType(typeof(Customer).FullName)).Message); } diff --git a/test/EFCore.Tests/ModelBuilding/ShadowEntityTypeTest.cs b/test/EFCore.Tests/ModelBuilding/ShadowEntityTypeTest.cs index 1f07402c917..d3f4afd6b6c 100644 --- a/test/EFCore.Tests/ModelBuilding/ShadowEntityTypeTest.cs +++ b/test/EFCore.Tests/ModelBuilding/ShadowEntityTypeTest.cs @@ -80,7 +80,7 @@ public virtual void Can_create_one_to_one_shadow_navigations_between_shadow_enti Assert.True(foreignKey.IsUnique); Assert.Equal( - CoreStrings.ShadowEntity("Order"), + CoreStrings.EntityRequiresKey("Order (Dictionary)"), Assert.Throws(() => modelBuilder.FinalizeModel()).Message); } @@ -98,7 +98,7 @@ public virtual void Can_create_one_to_many_shadow_navigations_between_shadow_ent Assert.False(foreignKey.IsUnique); Assert.Equal( - CoreStrings.ShadowEntity("Customer"), + CoreStrings.EntityRequiresKey("Customer (Dictionary)"), Assert.Throws(() => modelBuilder.FinalizeModel()).Message); } @@ -109,7 +109,8 @@ public virtual void Cannot_create_navigation_on_non_shadow_entity_targeting_shad var orderEntityType = modelBuilder.Entity(typeof(Order)); Assert.Equal( - CoreStrings.NavigationToShadowEntity("Customer", typeof(Order).ShortDisplayName(), "Customer"), + CoreStrings.NavigationSingleWrongClrType( + "Customer", typeof(Order).ShortDisplayName(), "Customer", "Dictionary"), Assert.Throws(() => orderEntityType.HasOne("Customer", "Customer")).Message); }