diff --git a/src/EFCore/Extensions/ConventionEntityTypeExtensions.cs b/src/EFCore/Extensions/ConventionEntityTypeExtensions.cs
index fe70512a738..35f76e856d8 100644
--- a/src/EFCore/Extensions/ConventionEntityTypeExtensions.cs
+++ b/src/EFCore/Extensions/ConventionEntityTypeExtensions.cs
@@ -509,7 +509,13 @@ public static IConventionProperty AddProperty(
public static IConventionProperty AddProperty(
[NotNull] this IConventionEntityType entityType, [NotNull] string name, [NotNull] Type propertyType,
bool setTypeConfigurationSource = true, bool fromDataAnnotation = false)
- => entityType.AddProperty(name, propertyType, null, setTypeConfigurationSource, fromDataAnnotation);
+ => ((EntityType)entityType).AddProperty(
+ name,
+ propertyType,
+ setTypeConfigurationSource
+ ? fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention
+ : (ConfigurationSource?)null,
+ fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);
///
/// Adds a property backed by and indexer to this entity type.
diff --git a/src/EFCore/Extensions/MutableEntityTypeExtensions.cs b/src/EFCore/Extensions/MutableEntityTypeExtensions.cs
index 882412c6546..f9e974c3687 100644
--- a/src/EFCore/Extensions/MutableEntityTypeExtensions.cs
+++ b/src/EFCore/Extensions/MutableEntityTypeExtensions.cs
@@ -470,7 +470,7 @@ public static IMutableProperty AddProperty(
/// The newly created property.
public static IMutableProperty AddProperty(
[NotNull] this IMutableEntityType entityType, [NotNull] string name, [NotNull] Type propertyType)
- => entityType.AddProperty(name, propertyType, null);
+ => ((EntityType)entityType).AddProperty(name, propertyType, ConfigurationSource.Explicit, ConfigurationSource.Explicit);
///
/// Adds a property backed up by an indexer to this entity type.
diff --git a/src/EFCore/Metadata/Builders/CollectionCollectionBuilder.cs b/src/EFCore/Metadata/Builders/CollectionCollectionBuilder.cs
index 808ec443fb8..e223c19cf93 100644
--- a/src/EFCore/Metadata/Builders/CollectionCollectionBuilder.cs
+++ b/src/EFCore/Metadata/Builders/CollectionCollectionBuilder.cs
@@ -118,21 +118,20 @@ public virtual EntityTypeBuilder UsingEntity(
Check.NotNull(configureRight, nameof(configureRight));
Check.NotNull(configureLeft, nameof(configureLeft));
- var existingjoinEntityType = (EntityType)
+ var existingJoinEntityType = (EntityType)
(LeftNavigation.ForeignKey?.DeclaringEntityType
?? RightNavigation.ForeignKey?.DeclaringEntityType);
EntityType joinEntityType = null;
- if (existingjoinEntityType != null)
+ if (existingJoinEntityType != null)
{
- if (existingjoinEntityType.ClrType == joinEntityClrType
- && !existingjoinEntityType.HasSharedClrType)
+ if (existingJoinEntityType.ClrType == joinEntityClrType
+ && !existingJoinEntityType.HasSharedClrType)
{
- joinEntityType = existingjoinEntityType;
+ joinEntityType = existingJoinEntityType;
}
else
{
- ModelBuilder.RemoveJoinEntityIfCreatedImplicitly(
- existingjoinEntityType, removeSkipNavigations: false, ConfigurationSource.Explicit);
+ ModelBuilder.RemoveImplicitJoinEntity(existingJoinEntityType);
}
}
@@ -183,8 +182,7 @@ public virtual EntityTypeBuilder UsingEntity(
}
else
{
- ModelBuilder.RemoveJoinEntityIfCreatedImplicitly(
- existingJoinEntityType, removeSkipNavigations: false, ConfigurationSource.Explicit);
+ ModelBuilder.RemoveImplicitJoinEntity(existingJoinEntityType);
}
}
@@ -281,13 +279,13 @@ protected virtual void Using([NotNull] IMutableForeignKey rightForeignKey, [NotN
var leftBuilder = ((SkipNavigation)LeftNavigation).Builder;
var rightBuilder = ((SkipNavigation)RightNavigation).Builder;
+ leftBuilder = leftBuilder.HasInverse(rightBuilder.Metadata, ConfigurationSource.Explicit);
+
leftBuilder = leftBuilder.HasForeignKey((ForeignKey)leftForeignKey, ConfigurationSource.Explicit);
rightBuilder = rightBuilder.HasForeignKey((ForeignKey)rightForeignKey, ConfigurationSource.Explicit);
- leftBuilder = leftBuilder.HasInverse(rightBuilder.Metadata, ConfigurationSource.Explicit);
-
LeftNavigation = leftBuilder.Metadata;
- RightNavigation = leftBuilder.Metadata.Inverse;
+ RightNavigation = rightBuilder.Metadata;
}
#region Hidden System.Object members
diff --git a/src/EFCore/Metadata/Builders/CollectionCollectionBuilder`.cs b/src/EFCore/Metadata/Builders/CollectionCollectionBuilder`.cs
index de098c5687d..5b2c84d3b34 100644
--- a/src/EFCore/Metadata/Builders/CollectionCollectionBuilder`.cs
+++ b/src/EFCore/Metadata/Builders/CollectionCollectionBuilder`.cs
@@ -88,8 +88,7 @@ public virtual EntityTypeBuilder UsingEntity(
}
else
{
- ModelBuilder.RemoveJoinEntityIfCreatedImplicitly(
- existingJoinEntityType, removeSkipNavigations: false, ConfigurationSource.Explicit);
+ ModelBuilder.RemoveImplicitJoinEntity(existingJoinEntityType);
}
}
@@ -139,8 +138,7 @@ public virtual EntityTypeBuilder UsingEntity(
}
else
{
- ModelBuilder.RemoveJoinEntityIfCreatedImplicitly(
- existingJoinEntityType, removeSkipNavigations: false, ConfigurationSource.Explicit);
+ ModelBuilder.RemoveImplicitJoinEntity(existingJoinEntityType);
}
}
diff --git a/src/EFCore/Metadata/Builders/CollectionNavigationBuilder.cs b/src/EFCore/Metadata/Builders/CollectionNavigationBuilder.cs
index 1b989d5ba2e..9268439bcc3 100644
--- a/src/EFCore/Metadata/Builders/CollectionNavigationBuilder.cs
+++ b/src/EFCore/Metadata/Builders/CollectionNavigationBuilder.cs
@@ -170,11 +170,14 @@ private InternalForeignKeyBuilder WithOneBuilder(MemberIdentity reference)
var navigationName = SkipNavigation.Name;
var declaringEntityType = (EntityType)DeclaringEntityType;
- declaringEntityType.Model.Builder
- .RemoveJoinEntityIfCreatedImplicitly(
- (EntityType)SkipNavigation.JoinEntityType,
- removeSkipNavigations: true,
- ConfigurationSource.Explicit);
+
+ if (SkipNavigation.Inverse != null)
+ {
+ ((EntityType)SkipNavigation.Inverse.DeclaringEntityType).Builder.HasNoSkipNavigation(
+ (SkipNavigation)SkipNavigation.Inverse, ConfigurationSource.Explicit);
+ }
+
+ declaringEntityType.Builder.HasNoSkipNavigation((SkipNavigation)SkipNavigation, ConfigurationSource.Explicit);
Builder = declaringEntityType.Builder
.HasRelationship(
diff --git a/src/EFCore/Metadata/Builders/IConventionEntityTypeBuilder.cs b/src/EFCore/Metadata/Builders/IConventionEntityTypeBuilder.cs
index 290021079c9..c60d30e7626 100644
--- a/src/EFCore/Metadata/Builders/IConventionEntityTypeBuilder.cs
+++ b/src/EFCore/Metadata/Builders/IConventionEntityTypeBuilder.cs
@@ -584,6 +584,25 @@ IConventionEntityTypeBuilder HasNoRelationship(
/// if the foreign key can be removed from this entity type.
bool CanRemoveRelationship([NotNull] IConventionForeignKey foreignKey, bool fromDataAnnotation = false);
+ ///
+ /// Removes a skip navigation from this entity type.
+ ///
+ /// The skip navigation to be removed.
+ /// Indicates whether the configuration was specified using a data annotation.
+ ///
+ /// The same builder instance if the skip navigation was removed,
+ /// otherwise.
+ ///
+ IConventionEntityTypeBuilder HasNoSkipNavigation([NotNull] ISkipNavigation skipNavigation, bool fromDataAnnotation = false);
+
+ ///
+ /// Returns a value indicating whether the skip navigation can be removed from this entity type.
+ ///
+ /// The skip navigation to be removed.
+ /// Indicates whether the configuration was specified using a data annotation.
+ /// if the skip navigation can be removed from this entity type.
+ bool CanRemoveSkipNavigation([NotNull] ISkipNavigation skipNavigation, bool fromDataAnnotation = false);
+
///
/// Returns a value indicating whether the given navigation can be added to this entity type.
///
diff --git a/src/EFCore/Metadata/Conventions/Infrastructure/ProviderConventionSetBuilder.cs b/src/EFCore/Metadata/Conventions/Infrastructure/ProviderConventionSetBuilder.cs
index 583b45fbc15..137915e67a4 100644
--- a/src/EFCore/Metadata/Conventions/Infrastructure/ProviderConventionSetBuilder.cs
+++ b/src/EFCore/Metadata/Conventions/Infrastructure/ProviderConventionSetBuilder.cs
@@ -179,11 +179,18 @@ public virtual ConventionSet CreateConventionSet()
conventionSet.NavigationAddedConventions.Add(relationshipDiscoveryConvention);
conventionSet.NavigationAddedConventions.Add(foreignKeyAttributeConvention);
+ var manyToManyJoinEntityTypeConvention = new ManyToManyJoinEntityTypeConvention(Dependencies);
conventionSet.SkipNavigationAddedConventions.Add(backingFieldConvention);
+ conventionSet.SkipNavigationAddedConventions.Add(manyToManyJoinEntityTypeConvention);
- conventionSet.NavigationRemovedConventions.Add(relationshipDiscoveryConvention);
+ conventionSet.SkipNavigationRemovedConventions.Add(manyToManyJoinEntityTypeConvention);
+
+ conventionSet.SkipNavigationInverseChangedConventions.Add(manyToManyJoinEntityTypeConvention);
- conventionSet.SkipNavigationAddedConventions.Add(new ManyToManyJoinEntityTypeConvention(Dependencies));
+ conventionSet.SkipNavigationForeignKeyChangedConventions.Add(manyToManyJoinEntityTypeConvention);
+ conventionSet.SkipNavigationForeignKeyChangedConventions.Add(keyDiscoveryConvention);
+
+ conventionSet.NavigationRemovedConventions.Add(relationshipDiscoveryConvention);
conventionSet.IndexAddedConventions.Add(foreignKeyIndexConvention);
diff --git a/src/EFCore/Metadata/Conventions/Internal/ConventionDispatcher.ImmediateConventionScope.cs b/src/EFCore/Metadata/Conventions/Internal/ConventionDispatcher.ImmediateConventionScope.cs
index d25d5e505e3..04490e7ed3c 100644
--- a/src/EFCore/Metadata/Conventions/Internal/ConventionDispatcher.ImmediateConventionScope.cs
+++ b/src/EFCore/Metadata/Conventions/Internal/ConventionDispatcher.ImmediateConventionScope.cs
@@ -779,13 +779,6 @@ public override IConventionForeignKey OnSkipNavigationForeignKeyChanged(
_foreignKeyConventionContext.ResetState(foreignKey);
foreach (var skipNavigationConvention in _conventionSet.SkipNavigationForeignKeyChangedConventions)
{
- if (navigationBuilder.Metadata.Builder == null
- || navigationBuilder.Metadata.ForeignKey != foreignKey)
- {
- Check.DebugAssert(false, "Foreign key changed");
- return null;
- }
-
skipNavigationConvention.ProcessSkipNavigationForeignKeyChanged(
navigationBuilder, foreignKey, oldForeignKey, _foreignKeyConventionContext);
if (_foreignKeyConventionContext.ShouldStopProcessing())
@@ -824,13 +817,6 @@ public override IConventionSkipNavigation OnSkipNavigationInverseChanged(
_skipNavigationConventionContext.ResetState(inverse);
foreach (var skipNavigationConvention in _conventionSet.SkipNavigationInverseChangedConventions)
{
- if (navigationBuilder.Metadata.Builder == null
- || navigationBuilder.Metadata.Inverse != inverse)
- {
- Check.DebugAssert(false, "inverse changed");
- return null;
- }
-
skipNavigationConvention.ProcessSkipNavigationInverseChanged(
navigationBuilder, inverse, oldInverse, _skipNavigationConventionContext);
if (_skipNavigationConventionContext.ShouldStopProcessing())
diff --git a/src/EFCore/Metadata/Conventions/KeyDiscoveryConvention.cs b/src/EFCore/Metadata/Conventions/KeyDiscoveryConvention.cs
index a575996d372..c5bfcc5836d 100644
--- a/src/EFCore/Metadata/Conventions/KeyDiscoveryConvention.cs
+++ b/src/EFCore/Metadata/Conventions/KeyDiscoveryConvention.cs
@@ -8,7 +8,6 @@
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
-using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Microsoft.EntityFrameworkCore.Utilities;
namespace Microsoft.EntityFrameworkCore.Metadata.Conventions
@@ -37,7 +36,8 @@ public class KeyDiscoveryConvention :
IForeignKeyRemovedConvention,
IForeignKeyPropertiesChangedConvention,
IForeignKeyUniquenessChangedConvention,
- IForeignKeyOwnershipChangedConvention
+ IForeignKeyOwnershipChangedConvention,
+ ISkipNavigationForeignKeyChangedConvention
{
private const string KeySuffix = "Id";
@@ -120,6 +120,16 @@ protected virtual void TryConfigurePrimaryKey([NotNull] IConventionEntityTypeBui
keyProperties.Add(extraProperty);
}
+ if (keyProperties.Count == 0)
+ {
+ var manyToManyForeignKeys = entityType.GetForeignKeys()
+ .Where(fk => fk.GetReferencingSkipNavigations().Any(n => n.IsCollection)).ToList();
+ if (manyToManyForeignKeys.Count() == 2)
+ {
+ keyProperties.AddRange(manyToManyForeignKeys.SelectMany(fk => fk.Properties));
+ }
+ }
+
ProcessKeyProperties(keyProperties, entityType);
if (keyProperties.Count > 0)
@@ -166,23 +176,13 @@ public static IEnumerable DiscoverKeyProperties(
// ReSharper restore PossibleMultipleEnumeration
}
- ///
- /// Called after an entity type is added to the model.
- ///
- /// The builder for the entity type.
- /// Additional information associated with convention execution.
+ ///
public virtual void ProcessEntityTypeAdded(
IConventionEntityTypeBuilder entityTypeBuilder,
IConventionContext context)
=> TryConfigurePrimaryKey(entityTypeBuilder);
- ///
- /// Called after the base type of an entity type changes.
- ///
- /// The builder for the entity type.
- /// The new base entity type.
- /// The old base entity type.
- /// Additional information associated with convention execution.
+ ///
public virtual void ProcessEntityTypeBaseTypeChanged(
IConventionEntityTypeBuilder entityTypeBuilder,
IConventionEntityType newBaseType,
@@ -197,23 +197,14 @@ public virtual void ProcessEntityTypeBaseTypeChanged(
TryConfigurePrimaryKey(entityTypeBuilder);
}
- ///
- /// Called after a property is added to the entity type.
- ///
- /// The builder for the property.
- /// Additional information associated with convention execution.
+ ///
public virtual void ProcessPropertyAdded(
IConventionPropertyBuilder propertyBuilder, IConventionContext context)
{
TryConfigurePrimaryKey(propertyBuilder.Metadata.DeclaringEntityType.Builder);
}
- ///
- /// Called after a key is removed.
- ///
- /// The builder for the entity type.
- /// The removed key.
- /// Additional information associated with convention execution.
+ ///
public virtual void ProcessKeyRemoved(
IConventionEntityTypeBuilder entityTypeBuilder, IConventionKey key, IConventionContext context)
{
@@ -223,11 +214,7 @@ public virtual void ProcessKeyRemoved(
}
}
- ///
- /// Called after a foreign key is added to the entity type.
- ///
- /// The builder for the foreign key.
- /// Additional information associated with convention execution.
+ ///
public virtual void ProcessForeignKeyAdded(
IConventionForeignKeyBuilder relationshipBuilder,
IConventionContext context)
@@ -238,13 +225,7 @@ public virtual void ProcessForeignKeyAdded(
}
}
- ///
- /// Called after the foreign key properties or principal key are changed.
- ///
- /// The builder for the foreign key.
- /// The old foreign key properties.
- /// The old principal key.
- /// Additional information associated with convention execution.
+ ///
public virtual void ProcessForeignKeyPropertiesChanged(
IConventionForeignKeyBuilder relationshipBuilder,
IReadOnlyList oldDependentProperties,
@@ -260,11 +241,8 @@ public virtual void ProcessForeignKeyPropertiesChanged(
}
}
- ///
- /// Called after the ownership value for a foreign key is changed.
- ///
- /// The builder for the foreign key.
- /// Additional information associated with convention execution.
+
+ ///
public virtual void ProcessForeignKeyOwnershipChanged(
IConventionForeignKeyBuilder relationshipBuilder,
IConventionContext context)
@@ -272,12 +250,7 @@ public virtual void ProcessForeignKeyOwnershipChanged(
TryConfigurePrimaryKey(relationshipBuilder.Metadata.DeclaringEntityType.Builder);
}
- ///
- /// Called after a foreign key is removed.
- ///
- /// The builder for the entity type.
- /// The removed foreign key.
- /// Additional information associated with convention execution.
+ ///
public virtual void ProcessForeignKeyRemoved(
IConventionEntityTypeBuilder entityTypeBuilder,
IConventionForeignKey foreignKey,
@@ -289,11 +262,7 @@ public virtual void ProcessForeignKeyRemoved(
}
}
- ///
- /// Called after the uniqueness for a foreign key is changed.
- ///
- /// The builder for the foreign key.
- /// Additional information associated with convention execution.
+ ///
public virtual void ProcessForeignKeyUniquenessChanged(
IConventionForeignKeyBuilder relationshipBuilder,
IConventionContext context)
@@ -303,5 +272,20 @@ public virtual void ProcessForeignKeyUniquenessChanged(
TryConfigurePrimaryKey(relationshipBuilder.Metadata.DeclaringEntityType.Builder);
}
}
+
+ ///
+ public virtual void ProcessSkipNavigationForeignKeyChanged(
+ IConventionSkipNavigationBuilder skipNavigationBuilder,
+ IConventionForeignKey foreignKey,
+ IConventionForeignKey oldForeignKey,
+ IConventionContext context)
+ {
+ var joinEntityTypeBuilder = skipNavigationBuilder.Metadata.ForeignKey?.DeclaringEntityType.Builder;
+ if (joinEntityTypeBuilder != null
+ && skipNavigationBuilder.Metadata.IsCollection)
+ {
+ TryConfigurePrimaryKey(joinEntityTypeBuilder);
+ }
+ }
}
}
diff --git a/src/EFCore/Metadata/Conventions/ManyToManyAssociationEntityTypeConvention.cs b/src/EFCore/Metadata/Conventions/ManyToManyAssociationEntityTypeConvention.cs
index a7f614616b9..b41c99c961c 100644
--- a/src/EFCore/Metadata/Conventions/ManyToManyAssociationEntityTypeConvention.cs
+++ b/src/EFCore/Metadata/Conventions/ManyToManyAssociationEntityTypeConvention.cs
@@ -17,10 +17,13 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Conventions
/// a many-to-many join entity with suitable foreign keys, sets the two
/// matching skip navigations to use those foreign keys.
///
- public class ManyToManyJoinEntityTypeConvention : ISkipNavigationAddedConvention, ISkipNavigationInverseChangedConvention
+ public class ManyToManyJoinEntityTypeConvention :
+ ISkipNavigationAddedConvention,
+ ISkipNavigationInverseChangedConvention,
+ ISkipNavigationForeignKeyChangedConvention,
+ ISkipNavigationRemovedConvention
{
private const string JoinEntityTypeNameTemplate = "{0}{1}";
- private const string JoinPropertyNameTemplate = "{0}_{1}";
///
/// Creates a new instance of .
@@ -41,9 +44,6 @@ public virtual void ProcessSkipNavigationAdded(
IConventionSkipNavigationBuilder skipNavigationBuilder,
IConventionContext context)
{
- Check.NotNull(skipNavigationBuilder, nameof(skipNavigationBuilder));
- Check.NotNull(context, nameof(context));
-
CreateJoinEntityType(skipNavigationBuilder);
}
@@ -54,28 +54,46 @@ public virtual void ProcessSkipNavigationInverseChanged(
IConventionSkipNavigation oldInverse,
IConventionContext context)
{
- Check.NotNull(skipNavigationBuilder, nameof(skipNavigationBuilder));
- Check.NotNull(context, nameof(context));
-
CreateJoinEntityType(skipNavigationBuilder);
}
- private void CreateJoinEntityType(
- IConventionSkipNavigationBuilder skipNavigationBuilder)
+ ///
+ public virtual void ProcessSkipNavigationForeignKeyChanged(
+ IConventionSkipNavigationBuilder skipNavigationBuilder,
+ IConventionForeignKey foreignKey,
+ IConventionForeignKey oldForeignKey,
+ IConventionContext context)
{
- var skipNavigation = (SkipNavigation)skipNavigationBuilder.Metadata;
- if (skipNavigation.JoinEntityType != null)
+ var joinEntityType = oldForeignKey?.DeclaringEntityType;
+ var navigation = skipNavigationBuilder.Metadata;
+ if (joinEntityType?.Builder != null
+ && navigation.IsCollection
+ && navigation.ForeignKey?.DeclaringEntityType != joinEntityType)
{
- return;
+ ((InternalModelBuilder)joinEntityType.Model.Builder).RemoveImplicitJoinEntity((EntityType)joinEntityType);
+ }
+ }
+
+ ///
+ public virtual void ProcessSkipNavigationRemoved(
+ IConventionEntityTypeBuilder entityTypeBuilder,
+ IConventionSkipNavigation navigation,
+ IConventionContext context)
+ {
+ var joinEntityType = navigation.ForeignKey?.DeclaringEntityType;
+ if (joinEntityType?.Builder != null
+ && navigation.IsCollection)
+ {
+ ((InternalModelBuilder)joinEntityType.Model.Builder).RemoveImplicitJoinEntity((EntityType)joinEntityType);
}
+ }
+ private void CreateJoinEntityType(IConventionSkipNavigationBuilder skipNavigationBuilder)
+ {
+ var skipNavigation = (SkipNavigation)skipNavigationBuilder.Metadata;
if (skipNavigation.ForeignKey != null
- || skipNavigation.TargetEntityType == skipNavigation.DeclaringEntityType
|| !skipNavigation.IsCollection)
{
- // do not create the join entity type for a self-referencing
- // skip navigation, or for one that is already "in use"
- // (i.e. has its Foreign Key assigned).
return;
}
@@ -84,9 +102,6 @@ private void CreateJoinEntityType(
|| inverseSkipNavigation.ForeignKey != null
|| !inverseSkipNavigation.IsCollection)
{
- // do not create the join entity type if
- // the inverse skip navigation is already "in use"
- // (i.e. has its Foreign Key assigned).
return;
}
@@ -97,7 +112,6 @@ private void CreateJoinEntityType(
var inverseEntityType = inverseSkipNavigation.DeclaringEntityType;
var model = declaringEntityType.Model;
- // create the join entity type
var joinEntityTypeName = string.Format(
JoinEntityTypeNameTemplate,
declaringEntityType.ShortName(),
@@ -114,74 +128,32 @@ private void CreateJoinEntityType(
var joinEntityTypeBuilder = model.Builder.SharedTypeEntity(
joinEntityTypeName, Model.DefaultPropertyBagType, ConfigurationSource.Convention);
- // Create left and right foreign keys from the outer entity types to
- // the join entity type and configure the skip navigations.
- // Roll back if any of this fails.
- var leftForeignKey =
- CreateSkipNavigationForeignKey(skipNavigation, joinEntityTypeBuilder);
+ var leftForeignKey = CreateSkipNavigationForeignKey(skipNavigation, joinEntityTypeBuilder);
if (leftForeignKey == null)
{
- model.Builder.HasNoEntityType(
- joinEntityTypeBuilder.Metadata, ConfigurationSource.Convention);
+ model.Builder.HasNoEntityType(joinEntityTypeBuilder.Metadata, ConfigurationSource.Convention);
return;
}
- var rightForeignKey =
- CreateSkipNavigationForeignKey(inverseSkipNavigation, joinEntityTypeBuilder);
+ var rightForeignKey = CreateSkipNavigationForeignKey(inverseSkipNavigation, joinEntityTypeBuilder);
if (rightForeignKey == null)
{
- // Removing the join entity type will also remove
- // the leftForeignKey created above.
- model.Builder.HasNoEntityType(
- joinEntityTypeBuilder.Metadata, ConfigurationSource.Convention);
+ model.Builder.HasNoEntityType(joinEntityTypeBuilder.Metadata, ConfigurationSource.Convention);
return;
}
skipNavigation.Builder.HasForeignKey(leftForeignKey, ConfigurationSource.Convention);
inverseSkipNavigation.Builder.HasForeignKey(rightForeignKey, ConfigurationSource.Convention);
-
- // Creating the primary key below also negates the need for an index on
- // the properties of leftForeignKey - that index is automatically removed.
- joinEntityTypeBuilder.PrimaryKey(
- leftForeignKey.Properties.Concat(rightForeignKey.Properties).ToList(),
- ConfigurationSource.Convention);
}
private static ForeignKey CreateSkipNavigationForeignKey(
SkipNavigation skipNavigation,
InternalEntityTypeBuilder joinEntityTypeBuilder)
- {
- var principalEntityType = skipNavigation.DeclaringEntityType;
- var principalKey = principalEntityType.FindPrimaryKey();
- if (principalKey == null)
- {
- return null;
- }
-
- var dependentEndForeignKeyPropertyNames = new List();
- var otherIdentifiers = joinEntityTypeBuilder.Metadata
- .GetDeclaredProperties().ToDictionary(p => p.Name, p => 0);
- foreach (var property in principalKey.Properties)
- {
- var propertyName = Uniquifier.Uniquify(
- string.Format(
- JoinPropertyNameTemplate,
- principalEntityType.ShortName(),
- property.Name),
- otherIdentifiers,
- int.MaxValue);
- dependentEndForeignKeyPropertyNames.Add(propertyName);
- otherIdentifiers.Add(propertyName, 0);
- }
-
- return joinEntityTypeBuilder
+ => joinEntityTypeBuilder
.HasRelationship(
- principalEntityType.Name,
- dependentEndForeignKeyPropertyNames,
- principalKey,
+ skipNavigation.DeclaringEntityType,
ConfigurationSource.Convention)
.IsUnique(false, ConfigurationSource.Convention)
.Metadata;
- }
}
}
diff --git a/src/EFCore/Metadata/Conventions/RelationshipDiscoveryConvention.cs b/src/EFCore/Metadata/Conventions/RelationshipDiscoveryConvention.cs
index f8789a0fc91..ba2155aaa40 100644
--- a/src/EFCore/Metadata/Conventions/RelationshipDiscoveryConvention.cs
+++ b/src/EFCore/Metadata/Conventions/RelationshipDiscoveryConvention.cs
@@ -747,21 +747,19 @@ private void RemoveNavigation(
}
else
{
- var joinEntityType = (EntityType)declaringEntityType
- .FindDeclaredSkipNavigation(navigationPropertyName)?
- .ForeignKey?.DeclaringEntityType;
- if (joinEntityType != null)
+ var skipNavigation = declaringEntityType.FindDeclaredSkipNavigation(navigationPropertyName);
+ if (skipNavigation != null)
{
- var modelBuilder = joinEntityType.Model.Builder;
- // The PropertyInfo underlying this skip navigation has become
- // ambiguous since we used it, so remove the join entity
- // if it was implicitly created.
- if (modelBuilder.RemoveJoinEntityIfCreatedImplicitly(
- joinEntityType, removeSkipNavigations: true, ConfigurationSource.Convention) == null)
+ var inverse = skipNavigation.Inverse;
+ if (declaringEntityType.Builder.HasNoSkipNavigation(skipNavigation) == null)
{
// Navigations of higher configuration source are not ambiguous
toRemoveFrom.Remove(navigationProperty);
}
+ else if (inverse?.Builder != null)
+ {
+ inverse.DeclaringEntityType.Builder.HasNoSkipNavigation(inverse);
+ }
}
}
}
diff --git a/src/EFCore/Metadata/Internal/EntityType.cs b/src/EFCore/Metadata/Internal/EntityType.cs
index e09c90f46ce..804ffdea3a4 100644
--- a/src/EFCore/Metadata/Internal/EntityType.cs
+++ b/src/EFCore/Metadata/Internal/EntityType.cs
@@ -388,6 +388,28 @@ public virtual EntityType SetBaseType([CanBeNull] EntityType newBaseType, Config
///
public virtual void OnTypeRemoved()
{
+ if (_foreignKeys.Count > 0)
+ {
+ foreach (var foreignKey in GetDeclaredForeignKeys().ToList())
+ {
+ if (foreignKey.PrincipalEntityType != this)
+ {
+ RemoveForeignKey(foreignKey);
+ }
+ }
+ }
+
+ if (_skipNavigations.Count > 0)
+ {
+ foreach (var skipNavigation in GetDeclaredSkipNavigations().ToList())
+ {
+ if (skipNavigation.TargetEntityType != this)
+ {
+ RemoveSkipNavigation(skipNavigation);
+ }
+ }
+ }
+
Builder = null;
_baseType?._directlyDerivedTypes.Remove(this);
@@ -2261,7 +2283,7 @@ public virtual Property AddProperty(
return AddProperty(
name,
propertyType,
- null,
+ ClrType?.GetMembersInHierarchy(name).FirstOrDefault(),
typeConfigurationSource,
configurationSource);
}
@@ -2341,7 +2363,8 @@ public virtual Property AddProperty(
}
else
{
- memberInfo = ClrType?.GetMembersInHierarchy(name).FirstOrDefault();
+ Check.DebugAssert(ClrType?.GetMembersInHierarchy(name).FirstOrDefault() == null,
+ "MemberInfo not supplied for non-shadow property");
}
if (memberInfo != null
@@ -3904,7 +3927,8 @@ IConventionIndex IConventionEntityType.AddIndex(
///
[DebuggerStepThrough]
IMutableProperty IMutableEntityType.AddProperty(string name, Type propertyType, MemberInfo memberInfo)
- => AddProperty(name, propertyType, memberInfo, ConfigurationSource.Explicit, ConfigurationSource.Explicit);
+ => AddProperty(name, propertyType, memberInfo ?? ClrType?.GetMembersInHierarchy(name).FirstOrDefault(),
+ ConfigurationSource.Explicit, ConfigurationSource.Explicit);
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -3918,7 +3942,7 @@ IConventionProperty IConventionEntityType.AddProperty(
=> AddProperty(
name,
propertyType,
- memberInfo,
+ memberInfo ?? ClrType?.GetMembersInHierarchy(name).FirstOrDefault(),
setTypeConfigurationSource
? fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention
: (ConfigurationSource?)null,
diff --git a/src/EFCore/Metadata/Internal/ForeignKey.cs b/src/EFCore/Metadata/Internal/ForeignKey.cs
index 0ff51a8729f..a73ae776eda 100644
--- a/src/EFCore/Metadata/Internal/ForeignKey.cs
+++ b/src/EFCore/Metadata/Internal/ForeignKey.cs
@@ -1089,6 +1089,11 @@ IConventionNavigation IConventionForeignKey.SetPrincipalToDependent(string name,
IConventionNavigation IConventionForeignKey.SetPrincipalToDependent(MemberInfo property, bool fromDataAnnotation)
=> HasPrincipalToDependent(property, fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);
+ ///
+ [DebuggerStepThrough]
+ IEnumerable IForeignKey.GetReferencingSkipNavigations()
+ => GetReferencingSkipNavigations();
+
///
/// 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/Metadata/Internal/InternalEntityTypeBuilder.cs b/src/EFCore/Metadata/Internal/InternalEntityTypeBuilder.cs
index 274c41da44a..b94d6b41ed9 100644
--- a/src/EFCore/Metadata/Internal/InternalEntityTypeBuilder.cs
+++ b/src/EFCore/Metadata/Internal/InternalEntityTypeBuilder.cs
@@ -659,10 +659,9 @@ private InternalPropertyBuilder Property(
var inverse = conflictingSkipNavigation.Inverse;
if (inverse?.Builder != null
- && inverse.DeclaringEntityType.Builder
- .CanRemoveSkipNavigation(inverse, configurationSource))
+ && inverse.GetConfigurationSource() != ConfigurationSource.Explicit)
{
- inverse.DeclaringEntityType.RemoveSkipNavigation(inverse);
+ inverse.DeclaringEntityType.Builder.HasNoSkipNavigation(inverse, configurationSource.Value);
}
conflictingSkipNavigation.DeclaringEntityType.Builder.HasNoSkipNavigation(
@@ -881,10 +880,9 @@ public virtual InternalServicePropertyBuilder ServiceProperty(
var inverse = conflictingSkipNavigation.Inverse;
if (inverse?.Builder != null
- && inverse.DeclaringEntityType.Builder
- .CanRemoveSkipNavigation(inverse, configurationSource))
+ && inverse.GetConfigurationSource() != ConfigurationSource.Explicit)
{
- inverse.DeclaringEntityType.RemoveSkipNavigation(inverse);
+ inverse.DeclaringEntityType.Builder.HasNoSkipNavigation(inverse, configurationSource.Value);
}
conflictingSkipNavigation.DeclaringEntityType.Builder.HasNoSkipNavigation(
@@ -1047,16 +1045,14 @@ public virtual InternalEntityTypeBuilder Ignore([NotNull] string name, Configura
{
var inverse = skipNavigation.Inverse;
if (inverse?.Builder != null
- && inverse.DeclaringEntityType.Builder
- .CanRemoveSkipNavigation(inverse, configurationSource))
+ && inverse.GetConfigurationSource() != ConfigurationSource.Explicit)
{
- inverse.SetInverse(null, configurationSource);
- inverse.DeclaringEntityType.RemoveSkipNavigation(inverse);
+ inverse.DeclaringEntityType.Builder.HasNoSkipNavigation(inverse, configurationSource);
}
Check.DebugAssert(skipNavigation.DeclaringEntityType == Metadata, "skipNavigation.DeclaringEntityType != Metadata");
- Metadata.RemoveSkipNavigation(skipNavigation);
+ Metadata.Builder.HasNoSkipNavigation(skipNavigation, configurationSource);
}
else
{
@@ -1117,18 +1113,14 @@ public virtual InternalEntityTypeBuilder Ignore([NotNull] string name, Configura
{
var inverse = skipNavigation.Inverse;
if (inverse?.Builder != null
- && configurationSource != inverse.GetConfigurationSource()
- && inverse.DeclaringEntityType.Builder
- .CanRemoveSkipNavigation(inverse, configurationSource))
+ && inverse.GetConfigurationSource() != ConfigurationSource.Explicit)
{
- inverse.SetInverse(null, configurationSource);
- inverse.DeclaringEntityType.RemoveSkipNavigation(inverse);
+ inverse.DeclaringEntityType.Builder.HasNoSkipNavigation(inverse, configurationSource);
}
- if (configurationSource.Overrides(skipNavigation.GetConfigurationSource())
- && skipNavigation.GetConfigurationSource() != ConfigurationSource.Explicit)
+ if (skipNavigation.GetConfigurationSource() != ConfigurationSource.Explicit)
{
- derivedType.RemoveSkipNavigation(skipNavigation);
+ derivedType.Builder.HasNoSkipNavigation(skipNavigation, configurationSource);
}
}
else
@@ -1467,7 +1459,7 @@ public virtual InternalEntityTypeBuilder HasBaseType(
return baseNavigation != null
&& n.TargetEntityType == baseNavigation.TargetEntityType;
},
- n => n.DeclaringEntityType.RemoveSkipNavigation(n));
+ n => n.DeclaringEntityType.Builder.HasNoSkipNavigation(n, ConfigurationSource.Explicit));
if (skipNavigationsToDetach != null)
{
@@ -1965,6 +1957,11 @@ public virtual InternalEntityTypeBuilder HasNoRelationship(
[NotNull] ForeignKey foreignKey,
ConfigurationSource configurationSource)
{
+ if (foreignKey.Builder == null)
+ {
+ return this;
+ }
+
var currentConfigurationSource = foreignKey.GetConfigurationSource();
if (!configurationSource.Overrides(currentConfigurationSource))
{
@@ -1982,6 +1979,11 @@ public virtual InternalEntityTypeBuilder HasNoRelationship(
}
}
+ if (foreignKey.Builder == null)
+ {
+ return this;
+ }
+
Metadata.RemoveForeignKey(foreignKey);
RemoveUnusedShadowProperties(foreignKey.Properties);
@@ -3673,8 +3675,7 @@ public virtual InternalSkipNavigationBuilder HasSkipNavigation(
public virtual InternalEntityTypeBuilder HasNoSkipNavigation(
[NotNull] SkipNavigation skipNavigation, ConfigurationSource configurationSource)
{
- var currentConfigurationSource = skipNavigation.GetConfigurationSource();
- if (!configurationSource.Overrides(currentConfigurationSource))
+ if (!CanRemoveSkipNavigation(skipNavigation, configurationSource))
{
return null;
}
@@ -3690,6 +3691,15 @@ public virtual InternalEntityTypeBuilder HasNoSkipNavigation(
return this;
}
+ ///
+ /// 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 CanRemoveSkipNavigation([NotNull] SkipNavigation skipNavigation, ConfigurationSource configurationSource)
+ => configurationSource.Overrides(skipNavigation.GetConfigurationSource());
+
private static InternalSkipNavigationBuilder DetachSkipNavigation(SkipNavigation skipNavigationToDetach)
{
var builder = skipNavigationToDetach?.Builder;
@@ -3698,7 +3708,7 @@ private static InternalSkipNavigationBuilder DetachSkipNavigation(SkipNavigation
return null;
}
- skipNavigationToDetach.DeclaringEntityType.RemoveSkipNavigation(skipNavigationToDetach);
+ skipNavigationToDetach.DeclaringEntityType.Builder.HasNoSkipNavigation(skipNavigationToDetach, ConfigurationSource.Explicit);
return builder;
}
@@ -3884,7 +3894,6 @@ public virtual IReadOnlyList GetOrCreateProperties(
return null;
}
- // TODO: Log that a shadow property is created
var propertyBuilder = Property(
required
? type
@@ -4835,6 +4844,18 @@ IConventionSkipNavigationBuilder IConventionEntityTypeBuilder.HasSkipNavigation(
collection,
onDependent);
+ ///
+ [DebuggerStepThrough]
+ IConventionEntityTypeBuilder IConventionEntityTypeBuilder.HasNoSkipNavigation(ISkipNavigation skipNavigation, bool fromDataAnnotation)
+ => HasNoSkipNavigation((SkipNavigation)skipNavigation,
+ fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);
+
+ ///
+ [DebuggerStepThrough]
+ bool IConventionEntityTypeBuilder.CanRemoveSkipNavigation(ISkipNavigation skipNavigation, bool fromDataAnnotation)
+ => CanRemoveSkipNavigation((SkipNavigation)skipNavigation,
+ fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);
+
///
/// 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/Metadata/Internal/InternalForeignKeyBuilder.cs b/src/EFCore/Metadata/Internal/InternalForeignKeyBuilder.cs
index 6e368d54030..dbf1c94ec8a 100644
--- a/src/EFCore/Metadata/Internal/InternalForeignKeyBuilder.cs
+++ b/src/EFCore/Metadata/Internal/InternalForeignKeyBuilder.cs
@@ -314,13 +314,12 @@ private InternalForeignKeyBuilder HasNavigations(
var inverse = conflictingSkipNavigation.Inverse;
if (inverse?.Builder != null
- && inverse.DeclaringEntityType.Builder
- .CanRemoveSkipNavigation(inverse, configurationSource))
+ && inverse.GetConfigurationSource() != ConfigurationSource.Explicit)
{
- inverse.DeclaringEntityType.RemoveSkipNavigation(inverse);
+ inverse.DeclaringEntityType.Builder.HasNoSkipNavigation(conflictingSkipNavigation, configurationSource);
}
- conflictingSkipNavigation.DeclaringEntityType.RemoveSkipNavigation(conflictingSkipNavigation);
+ conflictingSkipNavigation.DeclaringEntityType.Builder.HasNoSkipNavigation(conflictingSkipNavigation, configurationSource);
}
}
@@ -351,13 +350,12 @@ private InternalForeignKeyBuilder HasNavigations(
var inverse = conflictingSkipNavigation.Inverse;
if (inverse?.Builder != null
- && inverse.DeclaringEntityType.Builder
- .CanRemoveSkipNavigation(inverse, configurationSource))
+ && inverse.GetConfigurationSource() != ConfigurationSource.Explicit)
{
- inverse.DeclaringEntityType.RemoveSkipNavigation(inverse);
+ inverse.DeclaringEntityType.Builder.HasNoSkipNavigation(conflictingSkipNavigation, configurationSource);
}
- conflictingSkipNavigation.DeclaringEntityType.RemoveSkipNavigation(conflictingSkipNavigation);
+ conflictingSkipNavigation.DeclaringEntityType.Builder.HasNoSkipNavigation(conflictingSkipNavigation, configurationSource);
}
}
@@ -2191,6 +2189,9 @@ private InternalForeignKeyBuilder ReplaceForeignKey(
InternalForeignKeyBuilder newRelationshipBuilder;
using (var batch = Metadata.DeclaringEntityType.Model.ConventionDispatcher.DelayConventions())
{
+ var referencingSkipNavigations = Metadata.ReferencingSkipNavigations
+ ?.Select(n => (Navigation: n, ConfigurationSource: n.GetForeignKeyConfigurationSource().Value)).ToList();
+
newRelationshipBuilder = GetOrCreateRelationshipBuilder(
principalEntityTypeBuilder.Metadata,
dependentEntityTypeBuilder.Metadata,
@@ -2574,6 +2575,24 @@ private InternalForeignKeyBuilder ReplaceForeignKey(
?? newRelationshipBuilder;
}
+ if (referencingSkipNavigations != null)
+ {
+ foreach (var referencingNavigationTuple in referencingSkipNavigations)
+ {
+ var skipNavigation = referencingNavigationTuple.Navigation;
+ if (skipNavigation.Builder == null)
+ {
+ var navigationEntityType = skipNavigation.DeclaringEntityType;
+ skipNavigation = navigationEntityType.Builder == null
+ ? null
+ : navigationEntityType.FindSkipNavigation(skipNavigation.Name);
+ }
+
+ skipNavigation?.Builder.HasForeignKey(
+ newRelationshipBuilder.Metadata, referencingNavigationTuple.ConfigurationSource);
+ }
+ }
+
if (Metadata != newRelationshipBuilder.Metadata)
{
newRelationshipBuilder.MergeAnnotationsFrom(Metadata);
diff --git a/src/EFCore/Metadata/Internal/InternalModelBuilder.cs b/src/EFCore/Metadata/Internal/InternalModelBuilder.cs
index 788267521d1..5cd05fbd2bc 100644
--- a/src/EFCore/Metadata/Internal/InternalModelBuilder.cs
+++ b/src/EFCore/Metadata/Internal/InternalModelBuilder.cs
@@ -258,38 +258,21 @@ private InternalEntityTypeBuilder Entity(
/// 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 InternalModelBuilder RemoveJoinEntityIfCreatedImplicitly(
- [NotNull] EntityType joinEntityType,
- bool removeSkipNavigations,
- ConfigurationSource configurationSource)
+ public virtual InternalModelBuilder RemoveImplicitJoinEntity([NotNull] EntityType joinEntityType)
{
Check.NotNull(joinEntityType, nameof(joinEntityType));
- if (!joinEntityType.IsImplicitlyCreatedJoinEntityType)
+ if (joinEntityType.Builder == null)
{
- return null;
+ return this;
}
- Debug.Assert(joinEntityType.GetForeignKeys().Count() == 2,
- "Implicitly created join entity types should have exactly 2 foreign keys");
- foreach (var fk in joinEntityType.GetForeignKeys())
+ if (!joinEntityType.IsImplicitlyCreatedJoinEntityType)
{
- var skipNavigation = fk.GetReferencingSkipNavigations().FirstOrDefault();
- if (skipNavigation != null)
- {
- skipNavigation.SetForeignKey(null, configurationSource);
- skipNavigation.SetInverse(null, configurationSource);
-
- if (removeSkipNavigations
- && fk.PrincipalEntityType.Builder
- .CanRemoveSkipNavigation(skipNavigation, configurationSource))
- {
- fk.PrincipalEntityType.RemoveSkipNavigation(skipNavigation);
- }
- }
+ return null;
}
- return HasNoEntityType(joinEntityType, configurationSource);
+ return HasNoEntityType(joinEntityType, ConfigurationSource.Convention);
}
///
@@ -515,6 +498,12 @@ public virtual InternalModelBuilder HasNoEntityType([NotNull] EntityType entityT
Check.DebugAssert(removed != null, "removed is null");
}
+ foreach (var skipNavigation in entityType.GetDeclaredForeignKeys().SelectMany(fk => fk.GetReferencingSkipNavigations()).ToList())
+ {
+ var removed = skipNavigation.Builder.HasForeignKey(null, configurationSource);
+ Check.DebugAssert(removed != null, "removed is null");
+ }
+
foreach (var directlyDerivedType in entityType.GetDirectlyDerivedTypes().ToList())
{
var derivedEntityTypeBuilder = directlyDerivedType.Builder
diff --git a/src/EFCore/Metadata/Internal/InternalSkipNavigationBuilder.cs b/src/EFCore/Metadata/Internal/InternalSkipNavigationBuilder.cs
index 7a2946d191a..a73b38799a4 100644
--- a/src/EFCore/Metadata/Internal/InternalSkipNavigationBuilder.cs
+++ b/src/EFCore/Metadata/Internal/InternalSkipNavigationBuilder.cs
@@ -68,18 +68,13 @@ public virtual InternalSkipNavigationBuilder HasForeignKey([CanBeNull] ForeignKe
if (foreignKey != null)
{
foreignKey.UpdateConfigurationSource(configurationSource);
- }
- if (Metadata.JoinEntityType != null
- && foreignKey?.DeclaringEntityType != Metadata.JoinEntityType)
- {
- // Have reset the foreign key of a skip navigation on one side of an
- // join entity type to a different entity type. An implicit
- // join entity type is only useful if both sides are
- // configured - so, if it is implicit, remove that entity type
- // (which will also remove the other skip navigation's foreign key).
- Metadata.JoinEntityType.Model.Builder.RemoveJoinEntityIfCreatedImplicitly(
- Metadata.JoinEntityType, removeSkipNavigations: false, configurationSource);
+ if (Metadata.Inverse?.JoinEntityType != null
+ && Metadata.Inverse.JoinEntityType
+ != (Metadata.IsOnDependent ? foreignKey.PrincipalEntityType : foreignKey.DeclaringEntityType))
+ {
+ Metadata.Inverse.Builder.HasForeignKey(null, configurationSource);
+ }
}
Metadata.SetForeignKey(foreignKey, configurationSource);
@@ -107,12 +102,20 @@ public virtual bool CanSetForeignKey([CanBeNull] ForeignKey foreignKey, Configur
return true;
}
- return (Metadata.DeclaringEntityType
- == (Metadata.IsOnDependent ? foreignKey.DeclaringEntityType : foreignKey.PrincipalEntityType))
- && (Metadata.Inverse?.JoinEntityType == null
- || Metadata.Inverse.JoinEntityType.IsImplicitlyCreatedJoinEntityType == true
- || Metadata.Inverse.JoinEntityType
- == (Metadata.IsOnDependent ? foreignKey.PrincipalEntityType : foreignKey.DeclaringEntityType));
+ if (Metadata.DeclaringEntityType
+ != (Metadata.IsOnDependent ? foreignKey.DeclaringEntityType : foreignKey.PrincipalEntityType))
+ {
+ return false;
+ }
+
+ if (Metadata.Inverse?.JoinEntityType == null)
+ {
+ return true;
+ }
+
+ return Metadata.Inverse.JoinEntityType
+ == (Metadata.IsOnDependent ? foreignKey.PrincipalEntityType : foreignKey.DeclaringEntityType)
+ || Metadata.Inverse.Builder.CanSetForeignKey(null, configurationSource);
}
///
@@ -134,17 +137,20 @@ public virtual InternalSkipNavigationBuilder HasInverse(
inverse.UpdateConfigurationSource(configurationSource);
}
- if (Metadata.Inverse != null
- && Metadata.Inverse != inverse)
+ using (var batch = Metadata.DeclaringEntityType.Model.ConventionDispatcher.DelayConventions())
{
- Metadata.Inverse.SetInverse(null, configurationSource);
- }
+ if (Metadata.Inverse != null
+ && Metadata.Inverse != inverse)
+ {
+ Metadata.Inverse.SetInverse(null, configurationSource);
+ }
- Metadata.SetInverse(inverse, configurationSource);
+ Metadata.SetInverse(inverse, configurationSource);
- if (inverse != null)
- {
- inverse.SetInverse(Metadata, configurationSource);
+ if (inverse != null)
+ {
+ inverse.SetInverse(Metadata, configurationSource);
+ }
}
return this;
diff --git a/src/EFCore/Metadata/Internal/Model.cs b/src/EFCore/Metadata/Internal/Model.cs
index 4ac402bfd7d..fb0cf19b956 100644
--- a/src/EFCore/Metadata/Internal/Model.cs
+++ b/src/EFCore/Metadata/Internal/Model.cs
@@ -340,22 +340,6 @@ public virtual EntityType RemoveEntityType([CanBeNull] EntityType entityType)
AssertCanRemove(entityType);
- foreach (var foreignKey in entityType.GetDeclaredForeignKeys().ToList())
- {
- if (foreignKey.PrincipalEntityType != entityType)
- {
- entityType.RemoveForeignKey(foreignKey);
- }
- }
-
- foreach (var skipNavigation in entityType.GetSkipNavigations().ToList())
- {
- if (skipNavigation.TargetEntityType != entityType)
- {
- entityType.RemoveSkipNavigation(skipNavigation);
- }
- }
-
var entityTypeName = entityType.Name;
if (entityType.HasDefiningNavigation())
{
diff --git a/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs b/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs
index 6ff3f511caf..e3936979904 100644
--- a/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs
+++ b/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs
@@ -1125,15 +1125,15 @@ public virtual void Many_to_many_join_table_stored_in_snapshot()
+ @"
modelBuilder.Entity(""ManyToManyLeftManyToManyRight"", b =>
{
- b.Property(""ManyToManyLeft_Id"")
+ b.Property(""ManyToManyLeftId"")
.HasColumnType(""int"");
- b.Property(""ManyToManyRight_Id"")
+ b.Property(""ManyToManyRightId"")
.HasColumnType(""int"");
- b.HasKey(""ManyToManyLeft_Id"", ""ManyToManyRight_Id"");
+ b.HasKey(""ManyToManyLeftId"", ""ManyToManyRightId"");
- b.HasIndex(""ManyToManyRight_Id"");
+ b.HasIndex(""ManyToManyRightId"");
b.ToTable(""ManyToManyLeftManyToManyRight"");
});
@@ -1172,16 +1172,16 @@ public virtual void Many_to_many_join_table_stored_in_snapshot()
{
b.HasOne(""Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+ManyToManyLeft"", null)
.WithMany()
- .HasForeignKey(""ManyToManyLeft_Id"")
+ .HasForeignKey(""ManyToManyLeftId"")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne(""Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+ManyToManyRight"", null)
.WithMany()
- .HasForeignKey(""ManyToManyRight_Id"")
+ .HasForeignKey(""ManyToManyRightId"")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
- });", usingSystem: true),
+ });"),
model =>
{
var joinEntity = model.FindEntityType("ManyToManyLeftManyToManyRight");
@@ -1189,22 +1189,22 @@ public virtual void Many_to_many_join_table_stored_in_snapshot()
Assert.Collection(joinEntity.GetDeclaredProperties(),
p =>
{
- Assert.Equal("ManyToManyLeft_Id", p.Name);
+ Assert.Equal("ManyToManyLeftId", p.Name);
Assert.True(p.IsShadowProperty());
},
p =>
{
- Assert.Equal("ManyToManyRight_Id", p.Name);
+ Assert.Equal("ManyToManyRightId", p.Name);
Assert.True(p.IsShadowProperty());
});
Assert.Collection(joinEntity.FindDeclaredPrimaryKey().Properties,
p =>
{
- Assert.Equal("ManyToManyLeft_Id", p.Name);
+ Assert.Equal("ManyToManyLeftId", p.Name);
},
p =>
{
- Assert.Equal("ManyToManyRight_Id", p.Name);
+ Assert.Equal("ManyToManyRightId", p.Name);
});
Assert.Collection(joinEntity.GetDeclaredForeignKeys(),
fk =>
@@ -1218,7 +1218,7 @@ public virtual void Many_to_many_join_table_stored_in_snapshot()
Assert.Collection(fk.Properties,
p =>
{
- Assert.Equal("ManyToManyLeft_Id", p.Name);
+ Assert.Equal("ManyToManyLeftId", p.Name);
});
},
fk =>
@@ -1232,13 +1232,12 @@ public virtual void Many_to_many_join_table_stored_in_snapshot()
Assert.Collection(fk.Properties,
p =>
{
- Assert.Equal("ManyToManyRight_Id", p.Name);
+ Assert.Equal("ManyToManyRightId", p.Name);
});
});
});
}
-
[ConditionalFact]
public virtual void Can_override_table_name_for_many_to_many_join_table_stored_in_snapshot()
{
@@ -1256,15 +1255,15 @@ public virtual void Can_override_table_name_for_many_to_many_join_table_stored_i
+ @"
modelBuilder.Entity(""ManyToManyLeftManyToManyRight"", b =>
{
- b.Property(""ManyToManyLeft_Id"")
+ b.Property(""ManyToManyLeftId"")
.HasColumnType(""int"");
- b.Property(""ManyToManyRight_Id"")
+ b.Property(""ManyToManyRightId"")
.HasColumnType(""int"");
- b.HasKey(""ManyToManyLeft_Id"", ""ManyToManyRight_Id"");
+ b.HasKey(""ManyToManyLeftId"", ""ManyToManyRightId"");
- b.HasIndex(""ManyToManyRight_Id"");
+ b.HasIndex(""ManyToManyRightId"");
b.ToTable(""MyJoinTable"");
});
@@ -1303,16 +1302,16 @@ public virtual void Can_override_table_name_for_many_to_many_join_table_stored_i
{
b.HasOne(""Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+ManyToManyLeft"", null)
.WithMany()
- .HasForeignKey(""ManyToManyLeft_Id"")
+ .HasForeignKey(""ManyToManyLeftId"")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne(""Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+ManyToManyRight"", null)
.WithMany()
- .HasForeignKey(""ManyToManyRight_Id"")
+ .HasForeignKey(""ManyToManyRightId"")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
- });", usingSystem: true),
+ });"),
model =>
{
var joinEntity = model.FindEntityType("ManyToManyLeftManyToManyRight");
@@ -1321,22 +1320,22 @@ public virtual void Can_override_table_name_for_many_to_many_join_table_stored_i
Assert.Collection(joinEntity.GetDeclaredProperties(),
p =>
{
- Assert.Equal("ManyToManyLeft_Id", p.Name);
+ Assert.Equal("ManyToManyLeftId", p.Name);
Assert.True(p.IsShadowProperty());
},
p =>
{
- Assert.Equal("ManyToManyRight_Id", p.Name);
+ Assert.Equal("ManyToManyRightId", p.Name);
Assert.True(p.IsShadowProperty());
});
Assert.Collection(joinEntity.FindDeclaredPrimaryKey().Properties,
p =>
{
- Assert.Equal("ManyToManyLeft_Id", p.Name);
+ Assert.Equal("ManyToManyLeftId", p.Name);
},
p =>
{
- Assert.Equal("ManyToManyRight_Id", p.Name);
+ Assert.Equal("ManyToManyRightId", p.Name);
});
Assert.Collection(joinEntity.GetDeclaredForeignKeys(),
fk =>
@@ -1350,7 +1349,7 @@ public virtual void Can_override_table_name_for_many_to_many_join_table_stored_i
Assert.Collection(fk.Properties,
p =>
{
- Assert.Equal("ManyToManyLeft_Id", p.Name);
+ Assert.Equal("ManyToManyLeftId", p.Name);
});
},
fk =>
@@ -1364,7 +1363,7 @@ public virtual void Can_override_table_name_for_many_to_many_join_table_stored_i
Assert.Collection(fk.Properties,
p =>
{
- Assert.Equal("ManyToManyRight_Id", p.Name);
+ Assert.Equal("ManyToManyRightId", p.Name);
});
});
});
diff --git a/test/EFCore.Tests/Metadata/Conventions/ManyToManyAssociationEntityTypeConventionTest.cs b/test/EFCore.Tests/Metadata/Conventions/ManyToManyAssociationEntityTypeConventionTest.cs
index e24ea598bc5..e00f75b6d1a 100644
--- a/test/EFCore.Tests/Metadata/Conventions/ManyToManyAssociationEntityTypeConventionTest.cs
+++ b/test/EFCore.Tests/Metadata/Conventions/ManyToManyAssociationEntityTypeConventionTest.cs
@@ -26,7 +26,7 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Conventions
public class ManyToManyJoinEntityTypeConventionTest
{
[ConditionalFact]
- public void Join_entity_type_is_not_created_for_self_join()
+ public void Join_entity_type_is_created_for_self_join()
{
var modelBuilder = CreateInternalModeBuilder();
var manyToManySelf = modelBuilder.Entity(typeof(ManyToManySelf), ConfigurationSource.Convention);
@@ -45,7 +45,7 @@ public void Join_entity_type_is_not_created_for_self_join()
RunConvention(firstSkipNav);
- Assert.Empty(manyToManySelf.Metadata.Model.GetEntityTypes()
+ Assert.Single(manyToManySelf.Metadata.Model.GetEntityTypes()
.Where(et => et.IsImplicitlyCreatedJoinEntityType));
}
@@ -243,13 +243,6 @@ public void Join_entity_type_is_created()
Assert.Equal(2, joinEntityType.GetForeignKeys().Count());
Assert.Equal(manyToManyFirstForeignKey.DeclaringEntityType, joinEntityType);
Assert.Equal(manyToManySecondForeignKey.DeclaringEntityType, joinEntityType);
-
- var key = joinEntityType.FindPrimaryKey();
- Assert.Equal(
- new[] {
- nameof(ManyToManyFirst) + "_" + nameof(ManyToManyFirst.Id),
- nameof(ManyToManySecond) + "_" + nameof(ManyToManySecond.Id) },
- key.Properties.Select(p => p.Name));
}
public ListLoggerFactory ListLoggerFactory { get; }
diff --git a/test/EFCore.Tests/Metadata/Internal/EntityTypeTest.cs b/test/EFCore.Tests/Metadata/Internal/EntityTypeTest.cs
index 2c5b1a42c92..c475ec6f873 100644
--- a/test/EFCore.Tests/Metadata/Internal/EntityTypeTest.cs
+++ b/test/EFCore.Tests/Metadata/Internal/EntityTypeTest.cs
@@ -65,6 +65,7 @@ private class FakeEntityType : IEntityType
public IModel Model { get; }
public string Name { get; }
public bool HasSharedClrType { get; }
+ public bool IsPropertyBag { get; }
public Type ClrType { get; }
public IEntityType BaseType { get; }
public string DefiningNavigationName { get; }
diff --git a/test/EFCore.Tests/Metadata/Internal/InternalModelBuilderTest.cs b/test/EFCore.Tests/Metadata/Internal/InternalModelBuilderTest.cs
index bbef0222624..40defd292d5 100644
--- a/test/EFCore.Tests/Metadata/Internal/InternalModelBuilderTest.cs
+++ b/test/EFCore.Tests/Metadata/Internal/InternalModelBuilderTest.cs
@@ -348,10 +348,8 @@ public void Can_mark_type_as_owned_type()
Assert.Throws(() => modelBuilder.Owned(typeof(Details), ConfigurationSource.Explicit)).Message);
}
- [ConditionalTheory]
- [InlineData(true)]
- [InlineData(false)]
- public void Can_remove_implicitly_created_join_entity_type(bool removeSkipNavs)
+ [ConditionalFact]
+ public void Can_remove_implicitly_created_join_entity_type()
{
var model = new Model();
var modelBuilder = CreateModelBuilder(model);
@@ -401,31 +399,20 @@ public void Can_remove_implicitly_created_join_entity_type(bool removeSkipNavs)
var joinEntityType = joinEntityTypeBuilder.Metadata;
Assert.NotNull(joinEntityType);
-
- Assert.NotNull(modelBuilder.RemoveJoinEntityIfCreatedImplicitly(
- joinEntityType, removeSkipNavs, ConfigurationSource.Convention));
+ Assert.NotNull(modelBuilder.RemoveImplicitJoinEntity(joinEntityType));
Assert.Empty(model.GetEntityTypes()
.Where(e => e.IsImplicitlyCreatedJoinEntityType));
var leftSkipNav = manyToManyLeft.Metadata.FindDeclaredSkipNavigation(nameof(ManyToManyLeft.Rights));
var rightSkipNav = manyToManyRight.Metadata.FindDeclaredSkipNavigation(nameof(ManyToManyRight.Lefts));
- if (removeSkipNavs)
- {
- Assert.Null(leftSkipNav);
- Assert.Null(rightSkipNav);
- }
- else
- {
- Assert.NotNull(leftSkipNav);
- Assert.NotNull(rightSkipNav);
- }
+
+ Assert.NotNull(leftSkipNav);
+ Assert.NotNull(rightSkipNav);
}
- [ConditionalTheory]
- [InlineData(true)]
- [InlineData(false)]
- public void Cannot_remove_manually_created_join_entity_type(bool removeSkipNavs)
+ [ConditionalFact]
+ public void Cannot_remove_manually_created_join_entity_type()
{
var model = new Model();
var modelBuilder = CreateModelBuilder(model);
@@ -465,8 +452,7 @@ public void Cannot_remove_manually_created_join_entity_type(bool removeSkipNavs)
Assert.NotNull(joinEntityType);
Assert.Same(joinEntityType, skipNavOnRight.Metadata.JoinEntityType);
- Assert.Null(modelBuilder.RemoveJoinEntityIfCreatedImplicitly(
- joinEntityType, removeSkipNavs, ConfigurationSource.Convention));
+ Assert.Null(modelBuilder.RemoveImplicitJoinEntity(joinEntityType));
var leftSkipNav = manyToManyLeft.Metadata.FindDeclaredSkipNavigation(nameof(ManyToManyLeft.Rights));
var rightSkipNav = manyToManyRight.Metadata.FindDeclaredSkipNavigation(nameof(ManyToManyRight.Lefts));
diff --git a/test/EFCore.Tests/Metadata/Internal/InternalSkipNavigationBuilderTest.cs b/test/EFCore.Tests/Metadata/Internal/InternalSkipNavigationBuilderTest.cs
index 8348c97dd0f..bd8dd6300ba 100644
--- a/test/EFCore.Tests/Metadata/Internal/InternalSkipNavigationBuilderTest.cs
+++ b/test/EFCore.Tests/Metadata/Internal/InternalSkipNavigationBuilderTest.cs
@@ -126,7 +126,6 @@ public void Can_only_override_lower_or_equal_source_ForeignKey()
var builder = CreateInternalSkipNavigationBuilder();
IConventionSkipNavigation metadata = builder.Metadata;
- // the skip navigation is pointing to the automatically-generated join entity type
var originalFK = metadata.ForeignKey;
Assert.NotNull(originalFK);
Assert.Equal(ConfigurationSource.Convention, metadata.GetForeignKeyConfigurationSource());
@@ -137,17 +136,17 @@ public void Can_only_override_lower_or_equal_source_ForeignKey()
.IsUnique(false)
.Metadata;
- // skip navigation is unaffected by the FK created above
Assert.NotSame(fk, metadata.ForeignKey);
Assert.Same(originalFK, metadata.ForeignKey);
Assert.Equal(ConfigurationSource.Convention, metadata.GetForeignKeyConfigurationSource());
+ Assert.NotNull(metadata.Inverse.ForeignKey);
- // now explicitly assign the skip navigation's ForeignKey
Assert.True(builder.CanSetForeignKey(fk, ConfigurationSource.DataAnnotation));
Assert.NotNull(builder.HasForeignKey(fk, ConfigurationSource.DataAnnotation));
Assert.Equal(fk, metadata.ForeignKey);
Assert.Equal(ConfigurationSource.DataAnnotation, metadata.GetForeignKeyConfigurationSource());
+ Assert.Null(metadata.Inverse.ForeignKey);
Assert.True(builder.CanSetForeignKey(fk, ConfigurationSource.Convention));
Assert.False(builder.CanSetForeignKey(null, ConfigurationSource.Convention));
diff --git a/test/EFCore.Tests/ModelBuilding/ManyToManyTestBase.cs b/test/EFCore.Tests/ModelBuilding/ManyToManyTestBase.cs
index fce8058cbc6..9b3ca4ef12e 100644
--- a/test/EFCore.Tests/ModelBuilding/ManyToManyTestBase.cs
+++ b/test/EFCore.Tests/ModelBuilding/ManyToManyTestBase.cs
@@ -20,7 +20,7 @@ public abstract class ManyToManyTestBase : ModelBuilderTestBase
public virtual void Finds_existing_navigations_and_uses_associated_FK()
{
var modelBuilder = CreateModelBuilder();
- var model = modelBuilder.Model;
+ var model = (IModel)modelBuilder.Model;
modelBuilder.Entity().Ignore(c => c.Products);
modelBuilder.Entity().Ignore(p => p.Categories);
@@ -52,7 +52,7 @@ public virtual void Finds_existing_navigations_and_uses_associated_FK()
pcb => pcb.HasOne(pc => pc.Product).WithMany(),
pcb => pcb.HasOne(pc => pc.Category).WithMany(c => c.ProductCategories));
- modelBuilder.FinalizeModel();
+ model = modelBuilder.FinalizeModel();
Assert.Same(categoriesNavigation, productType.GetSkipNavigations().Single());
Assert.Same(productsNavigation, categoryType.GetSkipNavigations().Single());
@@ -65,7 +65,7 @@ public virtual void Finds_existing_navigations_and_uses_associated_FK()
public virtual void Finds_existing_navigations_and_uses_associated_FK_with_fields()
{
var modelBuilder = CreateModelBuilder();
- var model = modelBuilder.Model;
+ var model = (IModel)modelBuilder.Model;
modelBuilder.Entity(e =>
{
@@ -115,7 +115,7 @@ public virtual void Finds_existing_navigations_and_uses_associated_FK_with_field
jwf => jwf.HasOne(j => j.ManyToManyPrincipalWithField)
.WithMany());
- modelBuilder.FinalizeModel();
+ model = modelBuilder.FinalizeModel();
Assert.Same(principalToJoinNav, principalEntityType.GetSkipNavigations().Single());
Assert.Same(dependentToJoinNav, dependentEntityType.GetSkipNavigations().Single());
@@ -128,10 +128,11 @@ public virtual void Finds_existing_navigations_and_uses_associated_FK_with_field
public virtual void Join_type_is_automatically_configured_by_convention()
{
var modelBuilder = CreateModelBuilder();
- var model = modelBuilder.Model;
modelBuilder.Entity();
+ var model = modelBuilder.FinalizeModel();
+
var manyToManyA = model.FindEntityType(typeof(ImplicitManyToManyA));
var manyToManyB = model.FindEntityType(typeof(ImplicitManyToManyB));
var joinEntityType = model.GetEntityTypes()
@@ -157,11 +158,9 @@ public virtual void Join_type_is_automatically_configured_by_convention()
var key = joinEntityType.FindPrimaryKey();
Assert.Equal(
new[] {
- nameof(ImplicitManyToManyA) + "_" + nameof(ImplicitManyToManyA.Id),
- nameof(ImplicitManyToManyB) + "_" + nameof(ImplicitManyToManyB.Id) },
+ nameof(ImplicitManyToManyA) + nameof(ImplicitManyToManyA.Id),
+ nameof(ImplicitManyToManyB) + nameof(ImplicitManyToManyB.Id) },
key.Properties.Select(p => p.Name));
-
- modelBuilder.FinalizeModel();
}
[ConditionalFact]
@@ -174,8 +173,6 @@ public virtual void Join_type_is_not_automatically_configured_when_navigations_a
var hob = model.FindEntityType(typeof(Hob));
var nob = model.FindEntityType(typeof(Nob));
- Assert.NotNull(hob);
- Assert.NotNull(nob);
Assert.Empty(model.GetEntityTypes()
.Where(et => ((EntityType)et).IsImplicitlyCreatedJoinEntityType));
@@ -187,7 +184,6 @@ public virtual void Join_type_is_not_automatically_configured_when_navigations_a
public virtual void Can_configure_join_type_using_fluent_api()
{
var modelBuilder = CreateModelBuilder();
- var model = modelBuilder.Model;
modelBuilder.Entity().Ignore(c => c.Products);
modelBuilder.Entity().Ignore(p => p.Categories);
@@ -199,7 +195,7 @@ public virtual void Can_configure_join_type_using_fluent_api()
pcb => pcb.HasOne(pc => pc.Category).WithMany(c => c.ProductCategories),
pcb => pcb.HasKey(pc => new { pc.ProductId, pc.CategoryId }));
- modelBuilder.FinalizeModel();
+ var model = modelBuilder.FinalizeModel();
Assert.Equal(typeof(Category), manyToMany.Metadata.ClrType);
@@ -227,7 +223,6 @@ public virtual void Can_configure_join_type_using_fluent_api()
public virtual void Can_ignore_existing_navigations()
{
var modelBuilder = CreateModelBuilder();
- var model = modelBuilder.Model;
modelBuilder.Entity()
.HasMany(p => p.Products).WithMany(c => c.Categories);
@@ -237,20 +232,19 @@ public virtual void Can_ignore_existing_navigations()
// Issue #19550
modelBuilder.Ignore();
+ var model = modelBuilder.FinalizeModel();
+
var productType = model.FindEntityType(typeof(Product));
var categoryType = model.FindEntityType(typeof(Category));
Assert.Empty(productType.GetSkipNavigations());
Assert.Empty(categoryType.GetSkipNavigations());
-
- modelBuilder.FinalizeModel();
}
[ConditionalFact]
public virtual void Throws_for_conflicting_many_to_one_on_left()
{
var modelBuilder = CreateModelBuilder();
- var model = modelBuilder.Model;
// make sure we do not set up the automatic many-to-many relationship
modelBuilder.Entity().Ignore(e => e.Products);
@@ -273,7 +267,6 @@ public virtual void Throws_for_conflicting_many_to_one_on_left()
public virtual void Throws_for_conflicting_many_to_one_on_right()
{
var modelBuilder = CreateModelBuilder();
- var model = modelBuilder.Model;
// make sure we do not set up the automatic many-to-many relationship
modelBuilder.Entity().Ignore(e => e.Products);
@@ -296,7 +289,6 @@ public virtual void Throws_for_conflicting_many_to_one_on_right()
public virtual void Throws_for_many_to_many_with_only_one_navigation_configured()
{
var modelBuilder = CreateModelBuilder();
- var model = modelBuilder.Model;
Assert.Equal(
CoreStrings.MissingInverseManyToManyNavigation(
@@ -312,7 +304,6 @@ public virtual void Throws_for_many_to_many_with_only_one_navigation_configured(
public virtual void Navigation_properties_can_set_access_mode_using_expressions()
{
var modelBuilder = CreateModelBuilder();
- var model = modelBuilder.Model;
modelBuilder.Entity()
.HasMany(e => e.Dependents)
@@ -326,8 +317,13 @@ public virtual void Navigation_properties_can_set_access_mode_using_expressions(
.Navigation(e => e.ManyToManyPrincipals)
.UsePropertyAccessMode(PropertyAccessMode.Property);
- var principal = (IEntityType)model.FindEntityType(typeof(ManyToManyNavPrincipal));
- var dependent = (IEntityType)model.FindEntityType(typeof(NavDependent));
+ modelBuilder.Entity()
+ .Ignore(n => n.OneToOnePrincipal);
+
+ var model = modelBuilder.FinalizeModel();
+
+ var principal = model.FindEntityType(typeof(ManyToManyNavPrincipal));
+ var dependent = model.FindEntityType(typeof(NavDependent));
Assert.Equal(PropertyAccessMode.Field, principal.FindSkipNavigation("Dependents").GetPropertyAccessMode());
Assert.Equal(PropertyAccessMode.Property, dependent.FindSkipNavigation("ManyToManyPrincipals").GetPropertyAccessMode());
@@ -337,7 +333,6 @@ public virtual void Navigation_properties_can_set_access_mode_using_expressions(
public virtual void Navigation_properties_can_set_access_mode_using_navigation_names()
{
var modelBuilder = CreateModelBuilder();
- var model = modelBuilder.Model;
modelBuilder.Entity()
.HasMany("Dependents")
@@ -351,6 +346,11 @@ public virtual void Navigation_properties_can_set_access_mode_using_navigation_n
.Navigation("ManyToManyPrincipals")
.UsePropertyAccessMode(PropertyAccessMode.Property);
+ modelBuilder.Entity()
+ .Ignore(n => n.OneToOnePrincipal);
+
+ var model = modelBuilder.FinalizeModel();
+
var principal = (IEntityType)model.FindEntityType(typeof(ManyToManyNavPrincipal));
var dependent = (IEntityType)model.FindEntityType(typeof(NavDependent));
@@ -362,7 +362,6 @@ public virtual void Navigation_properties_can_set_access_mode_using_navigation_n
public virtual void Can_use_shared_Type_as_join_entity()
{
var modelBuilder = CreateModelBuilder();
- var model = modelBuilder.Model;
modelBuilder.Ignore();
modelBuilder.Ignore();
@@ -384,13 +383,20 @@ public virtual void Can_use_shared_Type_as_join_entity()
e => e.HasOne().WithMany(),
e => e.IndexerProperty("Payload"));
- var shared1 = modelBuilder.Model.FindEntityType("Shared1");
+ modelBuilder.Entity().HasKey(d => d.Id);
+ modelBuilder.Entity().HasKey(d => d.Id);
+ modelBuilder.Entity().HasKey(d => d.Id);
+ modelBuilder.Entity().HasKey(d => d.DependentWithFieldId);
+
+ var model = modelBuilder.FinalizeModel();
+
+ var shared1 = model.FindEntityType("Shared1");
Assert.NotNull(shared1);
Assert.Equal(2, shared1.GetForeignKeys().Count());
Assert.True(shared1.HasSharedClrType);
Assert.Equal(typeof(Dictionary), shared1.ClrType);
- var shared2 = modelBuilder.Model.FindEntityType("Shared2");
+ var shared2 = model.FindEntityType("Shared2");
Assert.NotNull(shared2);
Assert.Equal(2, shared2.GetForeignKeys().Count());
Assert.True(shared2.HasSharedClrType);
@@ -434,6 +440,13 @@ public virtual void UsingEntity_with_shared_type_passed_when_marked_as_shared_ty
r => r.HasOne().WithMany(),
l => l.HasOne().WithMany()).Metadata;
+ modelBuilder.Entity().HasKey(d => d.Id);
+ modelBuilder.Entity().HasKey(d => d.Id);
+ modelBuilder.Entity().HasKey(d => d.Id);
+ modelBuilder.Entity().HasKey(d => d.DependentWithFieldId);
+
+ var model = modelBuilder.FinalizeModel();
+
Assert.True(joinEntityType.HasSharedClrType);
Assert.Equal("Shared", joinEntityType.Name);
Assert.Equal(typeof(ManyToManyJoinWithFields), joinEntityType.ClrType);
@@ -454,6 +467,13 @@ public virtual void UsingEntity_with_shared_type_passes_when_configured_as_share
r => r.HasOne().WithMany(),
l => l.HasOne().WithMany()).Metadata;
+ modelBuilder.Entity().HasKey(d => d.Id);
+ modelBuilder.Entity().HasKey(d => d.Id);
+ modelBuilder.Entity().HasKey(d => d.Id);
+ modelBuilder.Entity().HasKey(d => d.DependentWithFieldId);
+
+ var model = modelBuilder.FinalizeModel();
+
Assert.True(joinEntityType.HasSharedClrType);
Assert.Equal("Shared", joinEntityType.Name);
Assert.Equal(typeof(ManyToManyJoinWithFields), joinEntityType.ClrType);