diff --git a/src/EFCore.SqlServer/Metadata/Conventions/SqlServerConventionSetBuilder.cs b/src/EFCore.SqlServer/Metadata/Conventions/SqlServerConventionSetBuilder.cs
index 0d861724b54..ded1ae336c0 100644
--- a/src/EFCore.SqlServer/Metadata/Conventions/SqlServerConventionSetBuilder.cs
+++ b/src/EFCore.SqlServer/Metadata/Conventions/SqlServerConventionSetBuilder.cs
@@ -73,6 +73,8 @@ public override ConventionSet CreateConventionSet()
ReplaceConvention(conventionSet.ForeignKeyRemovedConventions, valueGenerationConvention);
+ conventionSet.SkipNavigationForeignKeyChangedConventions.Add(new SqlServerOnDeleteConvention(Dependencies, RelationalDependencies));
+
conventionSet.IndexAddedConventions.Add(sqlServerInMemoryTablesConvention);
conventionSet.IndexAddedConventions.Add(sqlServerIndexConvention);
diff --git a/src/EFCore.SqlServer/Metadata/Conventions/SqlServerOnDeleteConvention.cs b/src/EFCore.SqlServer/Metadata/Conventions/SqlServerOnDeleteConvention.cs
new file mode 100644
index 00000000000..d1a93db97d0
--- /dev/null
+++ b/src/EFCore.SqlServer/Metadata/Conventions/SqlServerOnDeleteConvention.cs
@@ -0,0 +1,53 @@
+// 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.Linq;
+using JetBrains.Annotations;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
+
+// ReSharper disable once CheckNamespace
+namespace Microsoft.EntityFrameworkCore.Metadata.Conventions
+{
+ ///
+ /// A convention that configures the OnDelete behavior for foreign keys on the join entity type for
+ /// self-referencing skip navigations
+ ///
+ public class SqlServerOnDeleteConvention : ISkipNavigationForeignKeyChangedConvention
+ {
+ ///
+ /// Creates a new instance of .
+ ///
+ /// Parameter object containing dependencies for this convention.
+ /// Parameter object containing relational dependencies for this convention.
+ public SqlServerOnDeleteConvention(
+ [NotNull] ProviderConventionSetBuilderDependencies dependencies,
+ [NotNull] RelationalConventionSetBuilderDependencies relationalDependencies)
+ {
+ }
+
+ ///
+ public virtual void ProcessSkipNavigationForeignKeyChanged(
+ IConventionSkipNavigationBuilder skipNavigationBuilder,
+ IConventionForeignKey foreignKey,
+ IConventionForeignKey oldForeignKey,
+ IConventionContext context)
+ {
+ var selfReferencingSkipNavigation = skipNavigationBuilder.Metadata;
+ if (foreignKey == null
+ || foreignKey.DeleteBehavior != DeleteBehavior.Cascade
+ || selfReferencingSkipNavigation.Inverse == null
+ || selfReferencingSkipNavigation.TargetEntityType != selfReferencingSkipNavigation.DeclaringEntityType)
+ {
+ return;
+ }
+
+ if (selfReferencingSkipNavigation == selfReferencingSkipNavigation.DeclaringEntityType.GetDeclaredSkipNavigations()
+ .First(s => s == selfReferencingSkipNavigation || s == selfReferencingSkipNavigation.Inverse))
+ {
+ foreignKey.Builder.OnDelete(DeleteBehavior.ClientCascade);
+ selfReferencingSkipNavigation.Inverse.ForeignKey?.Builder.OnDelete(null);
+ }
+ }
+ }
+}
diff --git a/src/EFCore.SqlServer/Metadata/Conventions/SqlServerValueGenerationStrategyConvention.cs b/src/EFCore.SqlServer/Metadata/Conventions/SqlServerValueGenerationStrategyConvention.cs
index 2c61a5dea40..abb2817fa48 100644
--- a/src/EFCore.SqlServer/Metadata/Conventions/SqlServerValueGenerationStrategyConvention.cs
+++ b/src/EFCore.SqlServer/Metadata/Conventions/SqlServerValueGenerationStrategyConvention.cs
@@ -23,14 +23,8 @@ public SqlServerValueGenerationStrategyConvention(
[NotNull] ProviderConventionSetBuilderDependencies dependencies,
[NotNull] RelationalConventionSetBuilderDependencies relationalDependencies)
{
- Dependencies = dependencies;
}
- ///
- /// Parameter object containing service dependencies.
- ///
- protected virtual ProviderConventionSetBuilderDependencies Dependencies { get; }
-
///
/// Called after a model is initialized.
///
diff --git a/src/EFCore/Metadata/Conventions/ForeignKeyPropertyDiscoveryConvention.cs b/src/EFCore/Metadata/Conventions/ForeignKeyPropertyDiscoveryConvention.cs
index 43280026618..cad68e9eda2 100644
--- a/src/EFCore/Metadata/Conventions/ForeignKeyPropertyDiscoveryConvention.cs
+++ b/src/EFCore/Metadata/Conventions/ForeignKeyPropertyDiscoveryConvention.cs
@@ -475,7 +475,8 @@ private static IConventionProperty TryGetProperty(IConventionEntityType entityTy
{
foreach (var property in entityType.GetProperties())
{
- if ((!property.IsShadowProperty() || !ConfigurationSource.Convention.Overrides(property.GetConfigurationSource()))
+ if ((!(property.IsShadowProperty() || entityType.IsPropertyBag && property.IsIndexerProperty())
+ || !ConfigurationSource.Convention.Overrides(property.GetConfigurationSource()))
&& property.Name.Length == prefix.Length + suffix.Length
&& property.Name.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)
&& property.Name.EndsWith(suffix, StringComparison.OrdinalIgnoreCase))
@@ -801,14 +802,22 @@ public virtual void ProcessModelFinalizing(IConventionModelBuilder modelBuilder,
}
private static string GetPropertyBaseName(IConventionForeignKey foreignKey)
- => foreignKey.DependentToPrincipal?.Name ?? foreignKey.PrincipalEntityType.ShortName();
+ => foreignKey.DependentToPrincipal?.Name
+ ?? foreignKey.GetReferencingSkipNavigations().FirstOrDefault()?.Inverse?.Name
+ ?? foreignKey.PrincipalEntityType.ShortName();
private static bool HasUniquifiedProperties(IConventionForeignKey foreignKey)
{
var fkBaseName = GetPropertyBaseName(foreignKey);
for (var i = 0; i < foreignKey.Properties.Count; i++)
{
- var fkPropertyName = foreignKey.Properties[i].Name;
+ var property = foreignKey.Properties[i];
+ if (!ConfigurationSource.Convention.Overrides(property.GetConfigurationSource()))
+ {
+ return false;
+ }
+
+ var fkPropertyName = property.Name;
var pkPropertyName = foreignKey.PrincipalKey.Properties[i].Name;
if (fkPropertyName.Length != fkBaseName.Length + pkPropertyName.Length
|| !fkPropertyName.StartsWith(fkBaseName, StringComparison.Ordinal)
diff --git a/src/EFCore/Metadata/Conventions/IForeignKeyAddedConvention.cs b/src/EFCore/Metadata/Conventions/IForeignKeyAddedConvention.cs
index 15fdaad5f69..aba80b90b92 100644
--- a/src/EFCore/Metadata/Conventions/IForeignKeyAddedConvention.cs
+++ b/src/EFCore/Metadata/Conventions/IForeignKeyAddedConvention.cs
@@ -14,10 +14,10 @@ public interface IForeignKeyAddedConvention : IConvention
///
/// Called after a foreign key is added to the entity type.
///
- /// The builder for the foreign key.
+ /// The builder for the foreign key.
/// Additional information associated with convention execution.
void ProcessForeignKeyAdded(
- [NotNull] IConventionForeignKeyBuilder relationshipBuilder,
+ [NotNull] IConventionForeignKeyBuilder foreignKeyBuilder,
[NotNull] IConventionContext context);
}
}
diff --git a/src/EFCore/Metadata/Conventions/KeyDiscoveryConvention.cs b/src/EFCore/Metadata/Conventions/KeyDiscoveryConvention.cs
index c5bfcc5836d..7937efb6985 100644
--- a/src/EFCore/Metadata/Conventions/KeyDiscoveryConvention.cs
+++ b/src/EFCore/Metadata/Conventions/KeyDiscoveryConvention.cs
@@ -124,7 +124,7 @@ protected virtual void TryConfigurePrimaryKey([NotNull] IConventionEntityTypeBui
{
var manyToManyForeignKeys = entityType.GetForeignKeys()
.Where(fk => fk.GetReferencingSkipNavigations().Any(n => n.IsCollection)).ToList();
- if (manyToManyForeignKeys.Count() == 2)
+ if (manyToManyForeignKeys.Count == 2)
{
keyProperties.AddRange(manyToManyForeignKeys.SelectMany(fk => fk.Properties));
}
diff --git a/src/EFCore/Metadata/Conventions/ManyToManyJoinEntityTypeConvention.cs b/src/EFCore/Metadata/Conventions/ManyToManyJoinEntityTypeConvention.cs
index 7724c964e37..5b109fded6d 100644
--- a/src/EFCore/Metadata/Conventions/ManyToManyJoinEntityTypeConvention.cs
+++ b/src/EFCore/Metadata/Conventions/ManyToManyJoinEntityTypeConvention.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.Linq;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Infrastructure;
@@ -109,7 +110,12 @@ private void CreateJoinEntityType(IConventionSkipNavigationBuilder skipNavigatio
var inverseEntityType = inverseSkipNavigation.DeclaringEntityType;
var model = declaringEntityType.Model;
- var joinEntityTypeName = declaringEntityType.ShortName() + inverseEntityType.ShortName();
+ var joinEntityTypeName = declaringEntityType.ShortName();
+ var inverseName = inverseEntityType.ShortName();
+ joinEntityTypeName = StringComparer.Ordinal.Compare(joinEntityTypeName, inverseName) < 0
+ ? joinEntityTypeName + inverseName
+ : inverseName + joinEntityTypeName;
+
if (model.FindEntityType(joinEntityTypeName) != null)
{
var otherIdentifiers = model.GetEntityTypes().ToDictionary(et => et.Name, et => 0);
@@ -147,7 +153,8 @@ private static ForeignKey CreateSkipNavigationForeignKey(
.HasRelationship(
skipNavigation.DeclaringEntityType,
ConfigurationSource.Convention,
- required: true)
+ required: true,
+ skipNavigation.Inverse.Name)
.IsUnique(false, ConfigurationSource.Convention)
.Metadata;
}
diff --git a/src/EFCore/Metadata/Internal/InternalEntityTypeBuilder.cs b/src/EFCore/Metadata/Internal/InternalEntityTypeBuilder.cs
index 117b3932c92..1d39c2e3b09 100644
--- a/src/EFCore/Metadata/Internal/InternalEntityTypeBuilder.cs
+++ b/src/EFCore/Metadata/Internal/InternalEntityTypeBuilder.cs
@@ -2796,7 +2796,7 @@ private InternalForeignKeyBuilder HasRelationship(
targetEntityType.Builder,
dependentProperties: null,
principalKey: null,
- navigationToPrincipalName: navigationProperty?.GetSimpleMemberName(),
+ propertyBaseName: navigationProperty?.GetSimpleMemberName(),
required: required,
configurationSource: configurationSource);
}
@@ -2812,7 +2812,7 @@ private InternalForeignKeyBuilder HasRelationship(
this,
dependentProperties: null,
principalKey: null,
- navigationToPrincipalName: navigationProperty?.GetSimpleMemberName(),
+ propertyBaseName: navigationProperty?.GetSimpleMemberName(),
required: null,
configurationSource: configurationSource);
}
@@ -2904,8 +2904,9 @@ private InternalForeignKeyBuilder HasRelationship(
public virtual InternalForeignKeyBuilder HasRelationship(
[NotNull] EntityType principalEntityType,
ConfigurationSource configurationSource,
- bool? required = null)
- => HasRelationshipInternal(principalEntityType, principalKey: null, configurationSource, required);
+ bool? required = null,
+ [NotNull] string propertyBaseName = null)
+ => HasRelationshipInternal(principalEntityType, principalKey: null, configurationSource, required, propertyBaseName);
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -2917,14 +2918,16 @@ public virtual InternalForeignKeyBuilder HasRelationship(
[NotNull] EntityType principalEntityType,
[NotNull] Key principalKey,
ConfigurationSource configurationSource,
- bool? required = null)
- => HasRelationshipInternal(principalEntityType, principalKey, configurationSource, required);
+ bool? required = null,
+ [NotNull] string propertyBaseName = null)
+ => HasRelationshipInternal(principalEntityType, principalKey, configurationSource, required, propertyBaseName);
private InternalForeignKeyBuilder HasRelationshipInternal(
EntityType targetEntityType,
Key principalKey,
ConfigurationSource configurationSource,
- bool? required = null)
+ bool? required = null,
+ string propertyBaseName = null)
{
InternalForeignKeyBuilder relationship;
InternalForeignKeyBuilder newRelationship;
@@ -2934,7 +2937,7 @@ private InternalForeignKeyBuilder HasRelationshipInternal(
targetEntityType.Builder,
null,
principalKey,
- null,
+ propertyBaseName,
required,
configurationSource);
@@ -3394,14 +3397,14 @@ public virtual InternalForeignKeyBuilder CreateForeignKey(
[NotNull] InternalEntityTypeBuilder principalEntityTypeBuilder,
[CanBeNull] IReadOnlyList dependentProperties,
[CanBeNull] Key principalKey,
- [CanBeNull] string navigationToPrincipalName,
+ [CanBeNull] string propertyBaseName,
bool? required,
ConfigurationSource configurationSource)
{
using var batch = ModelBuilder.Metadata.ConventionDispatcher.DelayConventions();
var foreignKey = SetOrAddForeignKey(
- null, principalEntityTypeBuilder,
- dependentProperties, principalKey, navigationToPrincipalName, required, configurationSource);
+ foreignKey: null, principalEntityTypeBuilder, dependentProperties, principalKey,
+ propertyBaseName, required, configurationSource);
if (required.HasValue
&& foreignKey?.IsRequired == required.Value)
@@ -3422,14 +3425,14 @@ public virtual InternalForeignKeyBuilder UpdateForeignKey(
[NotNull] ForeignKey foreignKey,
[CanBeNull] IReadOnlyList dependentProperties,
[CanBeNull] Key principalKey,
- [CanBeNull] string navigationToPrincipalName,
+ [CanBeNull] string propertyBaseName,
bool? isRequired,
ConfigurationSource? configurationSource)
{
using var batch = ModelBuilder.Metadata.ConventionDispatcher.DelayConventions();
foreignKey = SetOrAddForeignKey(
- foreignKey, foreignKey.PrincipalEntityType.Builder,
- dependentProperties, principalKey, navigationToPrincipalName, isRequired, configurationSource);
+ foreignKey, foreignKey.PrincipalEntityType.Builder, dependentProperties, principalKey,
+ propertyBaseName, isRequired, configurationSource);
return (InternalForeignKeyBuilder)batch.Run(foreignKey)?.Builder;
}
@@ -3439,7 +3442,7 @@ private ForeignKey SetOrAddForeignKey(
InternalEntityTypeBuilder principalEntityTypeBuilder,
IReadOnlyList dependentProperties,
Key principalKey,
- string navigationToPrincipalName,
+ string propertyBaseName,
bool? isRequired,
ConfigurationSource? configurationSource)
{
@@ -3527,9 +3530,9 @@ private ForeignKey SetOrAddForeignKey(
}
}
- var baseName = string.IsNullOrEmpty(navigationToPrincipalName)
+ var baseName = string.IsNullOrEmpty(propertyBaseName)
? principalType.ShortName()
- : navigationToPrincipalName;
+ : propertyBaseName;
dependentProperties = CreateUniqueProperties(null, principalKey.Properties, isRequired ?? false, baseName);
}
@@ -3803,7 +3806,9 @@ public virtual bool ShouldReuniquifyTemporaryProperties([NotNull] ForeignKey for
foreignKey.PrincipalKey.Properties.Select(p => p.Name),
foreignKey.IsRequired
&& foreignKey.GetIsRequiredConfigurationSource().Overrides(ConfigurationSource.Convention),
- foreignKey.DependentToPrincipal?.Name ?? foreignKey.PrincipalEntityType.ShortName())
+ foreignKey.DependentToPrincipal?.Name
+ ?? foreignKey.ReferencingSkipNavigations?.FirstOrDefault()?.Inverse?.Name
+ ?? foreignKey.PrincipalEntityType.ShortName())
.Item1;
///
diff --git a/src/EFCore/Metadata/Internal/InternalForeignKeyBuilder.cs b/src/EFCore/Metadata/Internal/InternalForeignKeyBuilder.cs
index 20a316dbae0..7bf060a8d52 100644
--- a/src/EFCore/Metadata/Internal/InternalForeignKeyBuilder.cs
+++ b/src/EFCore/Metadata/Internal/InternalForeignKeyBuilder.cs
@@ -1622,7 +1622,7 @@ public virtual InternalForeignKeyBuilder ReuniquifyTemporaryProperties(bool forc
using var batch = Metadata.DeclaringEntityType.Model.ConventionDispatcher.DelayConventions();
var temporaryProperties = Metadata.Properties.Where(
- p => p.IsShadowProperty()
+ p => (p.IsShadowProperty() || p.DeclaringEntityType.IsPropertyBag && p.IsIndexerProperty())
&& ConfigurationSource.Convention.Overrides(p.GetConfigurationSource())).ToList();
var keysToDetach = temporaryProperties.SelectMany(
@@ -2465,7 +2465,8 @@ private InternalForeignKeyBuilder ReplaceForeignKey(
foreignKey,
dependentProperties?.Count == 0 ? null : dependentProperties,
principalKey,
- navigationToPrincipal?.Name,
+ navigationToPrincipal?.Name
+ ?? referencingSkipNavigations?.FirstOrDefault().Navigation?.Inverse?.Name,
isRequired,
configurationSource: null);
@@ -2833,6 +2834,7 @@ private InternalForeignKeyBuilder GetOrCreateRelationshipBuilder(
: null;
var removedForeignKeys = new List();
+ var referencingSkipNavigationName = Metadata.ReferencingSkipNavigations?.FirstOrDefault()?.Inverse?.Name;
if (Metadata.Builder == null)
{
removedForeignKeys.Add(Metadata);
@@ -2975,7 +2977,7 @@ private InternalForeignKeyBuilder GetOrCreateRelationshipBuilder(
principalEntityType.Builder,
dependentProperties,
principalKey,
- navigationToPrincipal?.Name,
+ navigationToPrincipal?.Name ?? referencingSkipNavigationName,
isRequired,
ConfigurationSource.Convention);
}
diff --git a/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs b/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs
index 74f1532581b..f71b40c5494 100644
--- a/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs
+++ b/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs
@@ -1124,15 +1124,15 @@ public virtual void Many_to_many_join_table_stored_in_snapshot()
+ @"
modelBuilder.Entity(""ManyToManyLeftManyToManyRight"", b =>
{
- b.Property(""ManyToManyLeftId"")
+ b.Property(""LeftsId"")
.HasColumnType(""int"");
- b.Property(""ManyToManyRightId"")
+ b.Property(""RightsId"")
.HasColumnType(""int"");
- b.HasKey(""ManyToManyLeftId"", ""ManyToManyRightId"");
+ b.HasKey(""LeftsId"", ""RightsId"");
- b.HasIndex(""ManyToManyRightId"");
+ b.HasIndex(""RightsId"");
b.ToTable(""ManyToManyLeftManyToManyRight"");
});
@@ -1171,13 +1171,13 @@ public virtual void Many_to_many_join_table_stored_in_snapshot()
{
b.HasOne(""Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+ManyToManyLeft"", null)
.WithMany()
- .HasForeignKey(""ManyToManyLeftId"")
+ .HasForeignKey(""LeftsId"")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne(""Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+ManyToManyRight"", null)
.WithMany()
- .HasForeignKey(""ManyToManyRightId"")
+ .HasForeignKey(""RightsId"")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});"),
@@ -1188,22 +1188,22 @@ public virtual void Many_to_many_join_table_stored_in_snapshot()
Assert.Collection(joinEntity.GetDeclaredProperties(),
p =>
{
- Assert.Equal("ManyToManyLeftId", p.Name);
+ Assert.Equal("LeftsId", p.Name);
Assert.True(p.IsShadowProperty());
},
p =>
{
- Assert.Equal("ManyToManyRightId", p.Name);
+ Assert.Equal("RightsId", p.Name);
Assert.True(p.IsShadowProperty());
});
Assert.Collection(joinEntity.FindDeclaredPrimaryKey().Properties,
p =>
{
- Assert.Equal("ManyToManyLeftId", p.Name);
+ Assert.Equal("LeftsId", p.Name);
},
p =>
{
- Assert.Equal("ManyToManyRightId", p.Name);
+ Assert.Equal("RightsId", p.Name);
});
Assert.Collection(joinEntity.GetDeclaredForeignKeys(),
fk =>
@@ -1217,7 +1217,7 @@ public virtual void Many_to_many_join_table_stored_in_snapshot()
Assert.Collection(fk.Properties,
p =>
{
- Assert.Equal("ManyToManyLeftId", p.Name);
+ Assert.Equal("LeftsId", p.Name);
});
},
fk =>
@@ -1231,7 +1231,7 @@ public virtual void Many_to_many_join_table_stored_in_snapshot()
Assert.Collection(fk.Properties,
p =>
{
- Assert.Equal("ManyToManyRightId", p.Name);
+ Assert.Equal("RightsId", p.Name);
});
});
});
@@ -1254,15 +1254,15 @@ public virtual void Can_override_table_name_for_many_to_many_join_table_stored_i
+ @"
modelBuilder.Entity(""ManyToManyLeftManyToManyRight"", b =>
{
- b.Property(""ManyToManyLeftId"")
+ b.Property(""LeftsId"")
.HasColumnType(""int"");
- b.Property(""ManyToManyRightId"")
+ b.Property(""RightsId"")
.HasColumnType(""int"");
- b.HasKey(""ManyToManyLeftId"", ""ManyToManyRightId"");
+ b.HasKey(""LeftsId"", ""RightsId"");
- b.HasIndex(""ManyToManyRightId"");
+ b.HasIndex(""RightsId"");
b.ToTable(""MyJoinTable"");
});
@@ -1301,13 +1301,13 @@ 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(""ManyToManyLeftId"")
+ .HasForeignKey(""LeftsId"")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne(""Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+ManyToManyRight"", null)
.WithMany()
- .HasForeignKey(""ManyToManyRightId"")
+ .HasForeignKey(""RightsId"")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});"),
@@ -1319,22 +1319,22 @@ public virtual void Can_override_table_name_for_many_to_many_join_table_stored_i
Assert.Collection(joinEntity.GetDeclaredProperties(),
p =>
{
- Assert.Equal("ManyToManyLeftId", p.Name);
+ Assert.Equal("LeftsId", p.Name);
Assert.True(p.IsShadowProperty());
},
p =>
{
- Assert.Equal("ManyToManyRightId", p.Name);
+ Assert.Equal("RightsId", p.Name);
Assert.True(p.IsShadowProperty());
});
Assert.Collection(joinEntity.FindDeclaredPrimaryKey().Properties,
p =>
{
- Assert.Equal("ManyToManyLeftId", p.Name);
+ Assert.Equal("LeftsId", p.Name);
},
p =>
{
- Assert.Equal("ManyToManyRightId", p.Name);
+ Assert.Equal("RightsId", p.Name);
});
Assert.Collection(joinEntity.GetDeclaredForeignKeys(),
fk =>
@@ -1348,7 +1348,7 @@ public virtual void Can_override_table_name_for_many_to_many_join_table_stored_i
Assert.Collection(fk.Properties,
p =>
{
- Assert.Equal("ManyToManyLeftId", p.Name);
+ Assert.Equal("LeftsId", p.Name);
});
},
fk =>
@@ -1362,7 +1362,7 @@ public virtual void Can_override_table_name_for_many_to_many_join_table_stored_i
Assert.Collection(fk.Properties,
p =>
{
- Assert.Equal("ManyToManyRightId", p.Name);
+ Assert.Equal("RightsId", p.Name);
});
});
});
diff --git a/test/EFCore.Specification.Tests/Query/ManyToManyQueryFixtureBase.cs b/test/EFCore.Specification.Tests/Query/ManyToManyQueryFixtureBase.cs
index 25dbf990eb6..a8f6591beff 100644
--- a/test/EFCore.Specification.Tests/Query/ManyToManyQueryFixtureBase.cs
+++ b/test/EFCore.Specification.Tests/Query/ManyToManyQueryFixtureBase.cs
@@ -165,6 +165,15 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con
.WithOne(e => e.ReferenceInverse)
.HasForeignKey(e => e.ReferenceInverseId);
+ // TODO: Remove UsingEntity
+ modelBuilder.Entity()
+ .HasMany(e => e.TwoSkipShared)
+ .WithMany(e => e.OneSkipShared)
+ .UsingEntity>(
+ "EntityOneEntityTwo",
+ r => r.HasOne().WithMany().HasForeignKey("EntityTwoId"),
+ l => l.HasOne().WithMany().HasForeignKey("EntityOneId"));
+
// Nav:2 Payload:No Join:Concrete Extra:None
modelBuilder.Entity()
.HasMany(e => e.TwoSkip)
@@ -197,7 +206,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con
.WithMany(e => e.SelfSkipPayloadRight)
.UsingEntity(
l => l.HasOne(x => x.Left).WithMany(x => x.JoinSelfPayloadLeft),
- r => r.HasOne(x => x.Right).WithMany(x => x.JoinSelfPayloadRight).OnDelete(DeleteBehavior.ClientCascade));
+ r => r.HasOne(x => x.Right).WithMany(x => x.JoinSelfPayloadRight));
// Nav:2 Payload:No Join:Concrete Extra:Inheritance
modelBuilder.Entity()
@@ -226,15 +235,17 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con
l => l.HasOne(x => x.Two).WithMany(e => e.JoinThreeFull));
// Nav:2 Payload:No Join:Shared Extra:Self-ref
+ // TODO: Remove UsingEntity
modelBuilder.Entity()
.HasMany(e => e.SelfSkipSharedLeft)
.WithMany(e => e.SelfSkipSharedRight)
.UsingEntity>(
"JoinTwoSelfShared",
l => l.HasOne().WithMany().HasForeignKey("LeftId"),
- r => r.HasOne().WithMany().HasForeignKey("RightId").OnDelete(DeleteBehavior.NoAction));
+ r => r.HasOne().WithMany().HasForeignKey("RightId"));
// Nav:2 Payload:No Join:Shared Extra:CompositeKey
+ // TODO: Remove UsingEntity
modelBuilder.Entity()
.HasMany(e => e.CompositeKeySkipShared)
.WithMany(e => e.TwoSkipShared)
@@ -253,9 +264,15 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con
r => r.HasOne(x => x.Three).WithMany(x => x.JoinCompositeKeyFull).IsRequired());
// Nav:2 Payload:No Join:Shared Extra:Inheritance
- modelBuilder.Entity().HasMany(e => e.RootSkipShared).WithMany(e => e.ThreeSkipShared);
+ // TODO: Remove UsingEntity
+ modelBuilder.Entity().HasMany(e => e.RootSkipShared).WithMany(e => e.ThreeSkipShared)
+ .UsingEntity>(
+ "EntityRootEntityThree",
+ r => r.HasOne().WithMany().HasForeignKey("EntityRootId"),
+ l => l.HasOne().WithMany().HasForeignKey("EntityThreeId"));
// Nav:2 Payload:No Join:Shared Extra:Inheritance,CompositeKey
+ // TODO: Remove UsingEntity
modelBuilder.Entity()
.HasMany(e => e.RootSkipShared)
.WithMany(e => e.CompositeKeySkipShared)
diff --git a/test/EFCore.SqlServer.FunctionalTests/ManyToManyTrackingSqlServerTestBase.cs b/test/EFCore.SqlServer.FunctionalTests/ManyToManyTrackingSqlServerTestBase.cs
index a3a1ad59ad2..9c0165cbba0 100644
--- a/test/EFCore.SqlServer.FunctionalTests/ManyToManyTrackingSqlServerTestBase.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/ManyToManyTrackingSqlServerTestBase.cs
@@ -10,7 +10,7 @@
namespace Microsoft.EntityFrameworkCore
{
public abstract class ManyToManyTrackingSqlServerTestBase : ManyToManyTrackingTestBase
- where TFixture : ManyToManyTrackingTestBase.ManyToManyTrackingFixtureBase
+ where TFixture : ManyToManyTrackingSqlServerTestBase.ManyToManyTrackingSqlServerFixtureBase
{
protected ManyToManyTrackingSqlServerTestBase(TFixture fixture)
: base(fixture)
diff --git a/test/EFCore.Tests/Metadata/Conventions/ManyToManyJoinEntityTypeConventionTest.cs b/test/EFCore.Tests/Metadata/Conventions/ManyToManyJoinEntityTypeConventionTest.cs
index e40b13fe9d6..b562c6e0744 100644
--- a/test/EFCore.Tests/Metadata/Conventions/ManyToManyJoinEntityTypeConventionTest.cs
+++ b/test/EFCore.Tests/Metadata/Conventions/ManyToManyJoinEntityTypeConventionTest.cs
@@ -45,8 +45,9 @@ public void Join_entity_type_is_created_for_self_join()
RunConvention(firstSkipNav);
- Assert.Single(manyToManySelf.Metadata.Model.GetEntityTypes()
- .Where(et => et.IsImplicitlyCreatedJoinEntityType));
+ var joinEntityType = manyToManySelf.Metadata.Model.GetEntityTypes()
+ .Single(et => et.IsImplicitlyCreatedJoinEntityType);
+ Assert.Equal("ManyToManySelfManyToManySelf", joinEntityType.Name);
}
[ConditionalFact]
@@ -222,7 +223,7 @@ public void Join_entity_type_is_created()
ConfigurationSource.Convention);
skipNavOnFirst.HasInverse(skipNavOnSecond.Metadata, ConfigurationSource.Convention);
- RunConvention(skipNavOnFirst);
+ RunConvention(skipNavOnSecond);
var joinEntityType = manyToManyFirst.Metadata.Model.GetEntityTypes()
.Single(et => et.IsImplicitlyCreatedJoinEntityType);
diff --git a/test/EFCore.Tests/ModelBuilding/ManyToManyTestBase.cs b/test/EFCore.Tests/ModelBuilding/ManyToManyTestBase.cs
index 07cb6273edf..d0ef4d2adc6 100644
--- a/test/EFCore.Tests/ModelBuilding/ManyToManyTestBase.cs
+++ b/test/EFCore.Tests/ModelBuilding/ManyToManyTestBase.cs
@@ -158,8 +158,8 @@ 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(ImplicitManyToManyB.As) + nameof(ImplicitManyToManyA.Id),
+ nameof(ImplicitManyToManyA.Bs) + nameof(ImplicitManyToManyB.Id) },
key.Properties.Select(p => p.Name));
Assert.DoesNotContain(joinEntityType.GetProperties(), p => !p.IsIndexerProperty());