diff --git a/src/EFCore.Relational/Metadata/Conventions/EntityTypeHierarchyMappingConvention.cs b/src/EFCore.Relational/Metadata/Conventions/EntityTypeHierarchyMappingConvention.cs
index 76c191d9a47..9b870b32a38 100644
--- a/src/EFCore.Relational/Metadata/Conventions/EntityTypeHierarchyMappingConvention.cs
+++ b/src/EFCore.Relational/Metadata/Conventions/EntityTypeHierarchyMappingConvention.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
+using System.Linq;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
@@ -42,6 +43,15 @@ public virtual void ProcessModelFinalizing(IConventionModelBuilder modelBuilder,
&& (tableName != entityType.BaseType.GetTableName()
|| schema != entityType.BaseType.GetSchema()))
{
+ var pk = entityType.FindPrimaryKey();
+ if (pk != null
+ && !entityType.FindDeclaredForeignKeys(pk.Properties)
+ .Any(fk => fk.PrincipalKey.IsPrimaryKey() && fk.PrincipalEntityType.IsAssignableFrom(entityType)))
+ {
+ entityType.Builder.HasRelationship(entityType.BaseType, pk.Properties, entityType.BaseType.FindPrimaryKey())
+ .IsUnique(true);
+ }
+
nonTphRoots.Add(entityType.GetRootType());
}
diff --git a/src/EFCore.Relational/Metadata/Conventions/SharedTableConvention.cs b/src/EFCore.Relational/Metadata/Conventions/SharedTableConvention.cs
index a90311435c4..9daa096b0fe 100644
--- a/src/EFCore.Relational/Metadata/Conventions/SharedTableConvention.cs
+++ b/src/EFCore.Relational/Metadata/Conventions/SharedTableConvention.cs
@@ -373,8 +373,14 @@ private void TryUniquifyForeignKeyNames(
in StoreObjectIdentifier storeObject,
int maxLength)
{
- foreach (var foreignKey in entityType.GetDeclaredForeignKeys())
+ foreach (var foreignKey in entityType.GetForeignKeys())
{
+ if (foreignKey.DeclaringEntityType != entityType
+ && StoreObjectIdentifier.Create(foreignKey.DeclaringEntityType, StoreObjectType.Table) == storeObject)
+ {
+ continue;
+ }
+
var principalTable = foreignKey.PrincipalKey.IsPrimaryKey()
? StoreObjectIdentifier.Create(foreignKey.PrincipalEntityType, StoreObjectType.Table)
: StoreObjectIdentifier.Create(foreignKey.PrincipalKey.DeclaringEntityType, StoreObjectType.Table);
@@ -408,6 +414,12 @@ private void TryUniquifyForeignKeyNames(
continue;
}
+ if (!otherForeignKey.DeclaringEntityType.IsAssignableFrom(entityType)
+ && !entityType.IsAssignableFrom(otherForeignKey.DeclaringEntityType))
+ {
+ continue;
+ }
+
var newOtherForeignKeyName = TryUniquify(otherForeignKey, foreignKeyName, foreignKeys, maxLength);
if (newOtherForeignKeyName != null)
{
diff --git a/src/EFCore.Relational/Metadata/Internal/RelationalForeignKeyExtensions.cs b/src/EFCore.Relational/Metadata/Internal/RelationalForeignKeyExtensions.cs
index 63bc9b2fc39..b5e55e7ba5d 100644
--- a/src/EFCore.Relational/Metadata/Internal/RelationalForeignKeyExtensions.cs
+++ b/src/EFCore.Relational/Metadata/Internal/RelationalForeignKeyExtensions.cs
@@ -139,7 +139,9 @@ public static bool AreCompatible(
return false;
}
- if (foreignKey.DeleteBehavior != duplicateForeignKey.DeleteBehavior)
+ var referentialAction = RelationalModel.ToReferentialAction(foreignKey.DeleteBehavior);
+ var duplicateReferentialAction = RelationalModel.ToReferentialAction(duplicateForeignKey.DeleteBehavior);
+ if (referentialAction != duplicateReferentialAction)
{
if (shouldThrow)
{
@@ -151,8 +153,8 @@ public static bool AreCompatible(
duplicateForeignKey.DeclaringEntityType.DisplayName(),
foreignKey.DeclaringEntityType.GetSchemaQualifiedTableName(),
foreignKey.GetConstraintName(storeObject, principalTable.Value),
- foreignKey.DeleteBehavior,
- duplicateForeignKey.DeleteBehavior));
+ referentialAction,
+ duplicateReferentialAction));
}
return false;
diff --git a/src/EFCore.Relational/Metadata/Internal/RelationalModel.cs b/src/EFCore.Relational/Metadata/Internal/RelationalModel.cs
index c3deafae37d..ac81bb44798 100644
--- a/src/EFCore.Relational/Metadata/Internal/RelationalModel.cs
+++ b/src/EFCore.Relational/Metadata/Internal/RelationalModel.cs
@@ -750,6 +750,12 @@ private static void PopulateConstraints(Table table)
var storeObject = StoreObjectIdentifier.Table(table.Name, table.Schema);
foreach (var entityTypeMapping in ((ITable)table).EntityTypeMappings)
{
+ if (!entityTypeMapping.IncludesDerivedTypes
+ && entityTypeMapping.EntityType.GetTableMappings().Any(m => m.IncludesDerivedTypes))
+ {
+ continue;
+ }
+
var entityType = (IConventionEntityType)entityTypeMapping.EntityType;
foreach (var foreignKey in entityType.GetForeignKeys())
{
@@ -1061,7 +1067,13 @@ private static void PopulateRowInternalForeignKeys(TableBase table)
}
}
- private static ReferentialAction ToReferentialAction(DeleteBehavior deleteBehavior)
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public static ReferentialAction ToReferentialAction(DeleteBehavior deleteBehavior)
{
switch (deleteBehavior)
{
diff --git a/src/EFCore.Relational/Query/SqlExpressionFactory.cs b/src/EFCore.Relational/Query/SqlExpressionFactory.cs
index f3fbb45bacc..16ca637a883 100644
--- a/src/EFCore.Relational/Query/SqlExpressionFactory.cs
+++ b/src/EFCore.Relational/Query/SqlExpressionFactory.cs
@@ -948,9 +948,15 @@ private void AddOptionalDependentConditions(
// other dependents.
foreach (var referencingFk in entityType.GetReferencingForeignKeys())
{
+ if (referencingFk.PrincipalEntityType.IsAssignableFrom(entityType))
+ {
+ continue;
+ }
+
var otherSelectExpression = new SelectExpression(entityType, this);
- var sameTable = table.IsOptional(referencingFk.DeclaringEntityType);
+ var sameTable = table.EntityTypeMappings.Any(m => m.EntityType == referencingFk.DeclaringEntityType)
+ && table.IsOptional(referencingFk.DeclaringEntityType);
AddInnerJoin(
otherSelectExpression, referencingFk,
sameTable ? table : null);
diff --git a/src/EFCore.Relational/Update/Internal/CommandBatchPreparer.cs b/src/EFCore.Relational/Update/Internal/CommandBatchPreparer.cs
index 8ce48b76155..8a3c5abcbf2 100644
--- a/src/EFCore.Relational/Update/Internal/CommandBatchPreparer.cs
+++ b/src/EFCore.Relational/Update/Internal/CommandBatchPreparer.cs
@@ -177,7 +177,6 @@ protected virtual IEnumerable CreateModificationCommands(
var mappings = (IReadOnlyCollection)entry.EntityType.GetTableMappings();
var mappingCount = mappings.Count;
ModificationCommand firstCommand = null;
- var relatedCommands = mappingCount > 1 ? new List(mappingCount) : null;
foreach (var mapping in mappings)
{
var table = mapping.Table;
@@ -216,33 +215,12 @@ protected virtual IEnumerable CreateModificationCommands(
Check.DebugAssert(firstCommand == null, "firstCommand == null");
firstCommand = command;
}
-
- if (relatedCommands != null)
- {
- relatedCommands.Add(command);
- }
}
if (firstCommand == null)
{
throw new InvalidOperationException(RelationalStrings.ReadonlyEntitySaved(entry.EntityType.DisplayName()));
}
-
- if (relatedCommands != null)
- {
- if (firstCommand.EntityState == EntityState.Deleted)
- {
- relatedCommands.Reverse();
- }
-
- var previousCommand = relatedCommands[0];
- for (var i = 1; i < relatedCommands.Count; i++)
- {
- var relatedCommand = relatedCommands[i];
- relatedCommand.Predecessor = previousCommand;
- previousCommand = relatedCommand;
- }
- }
}
if (sharedTablesCommandsMap != null)
@@ -569,12 +547,6 @@ private void AddForeignKeyEdges(
{
foreach (var command in commandGraph.Vertices)
{
- if (command.Predecessor != null)
- {
- // This is usually an implicit relationship between TPT rows for the same entity
- commandGraph.AddEdge(command.Predecessor, command, null);
- }
-
switch (command.EntityState)
{
case EntityState.Modified:
@@ -585,9 +557,8 @@ private void AddForeignKeyEdges(
var entry = command.Entries[entryIndex];
foreach (var foreignKey in entry.EntityType.GetForeignKeys())
{
- var constraints = foreignKey.GetMappedConstraints();
-
- if (!constraints.Any()
+ if (!foreignKey.GetMappedConstraints()
+ .Any(c => c.Table.Name == command.TableName && c.Table.Schema == command.Schema)
|| (command.EntityState == EntityState.Modified
&& !foreignKey.Properties.Any(p => entry.IsModified(p))))
{
diff --git a/src/EFCore.Relational/Update/ModificationCommand.cs b/src/EFCore.Relational/Update/ModificationCommand.cs
index 1275477c6c7..4d852d054dc 100644
--- a/src/EFCore.Relational/Update/ModificationCommand.cs
+++ b/src/EFCore.Relational/Update/ModificationCommand.cs
@@ -90,11 +90,6 @@ public ModificationCommand(
///
public virtual string Schema { get; }
- ///
- /// The command that needs to be executed before this one.
- ///
- public virtual ModificationCommand Predecessor { get; [param: CanBeNull] set; }
-
///
/// The s that represent the entities that are mapped to the row
/// to update.
diff --git a/src/EFCore.SqlServer/Extensions/SqlServerPropertyExtensions.cs b/src/EFCore.SqlServer/Extensions/SqlServerPropertyExtensions.cs
index e0f91a42f11..14ef5a2bdac 100644
--- a/src/EFCore.SqlServer/Extensions/SqlServerPropertyExtensions.cs
+++ b/src/EFCore.SqlServer/Extensions/SqlServerPropertyExtensions.cs
@@ -2,6 +2,7 @@
// 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;
using Microsoft.EntityFrameworkCore.Metadata;
@@ -335,7 +336,7 @@ public static SqlServerValueGenerationStrategy GetValueGenerationStrategy(
}
if (property.ValueGenerated != ValueGenerated.OnAdd
- || property.IsForeignKey()
+ || property.GetContainingForeignKeys().Any(fk => !fk.IsBaseLinking())
|| property.GetDefaultValue(storeObject) != null
|| property.GetDefaultValueSql(storeObject) != null
|| property.GetComputedColumnSql(storeObject) != null)
diff --git a/src/EFCore.SqlServer/Metadata/Conventions/SqlServerOnDeleteConvention.cs b/src/EFCore.SqlServer/Metadata/Conventions/SqlServerOnDeleteConvention.cs
index a1bf026392a..ad5b16bf42d 100644
--- a/src/EFCore.SqlServer/Metadata/Conventions/SqlServerOnDeleteConvention.cs
+++ b/src/EFCore.SqlServer/Metadata/Conventions/SqlServerOnDeleteConvention.cs
@@ -46,6 +46,11 @@ protected override DeleteBehavior GetTargetDeleteBehavior(IConventionForeignKey
return deleteBehavior;
}
+ if (foreignKey.IsBaseLinking())
+ {
+ return DeleteBehavior.ClientCascade;
+ }
+
var selfReferencingSkipNavigation = foreignKey.GetReferencingSkipNavigations()
.FirstOrDefault(s => s.Inverse != null && s.TargetEntityType == s.DeclaringEntityType);
if (selfReferencingSkipNavigation == null)
diff --git a/src/EFCore/ChangeTracking/Internal/StateManager.cs b/src/EFCore/ChangeTracking/Internal/StateManager.cs
index 1de65f14d08..6f2d2ec4a1f 100644
--- a/src/EFCore/ChangeTracking/Internal/StateManager.cs
+++ b/src/EFCore/ChangeTracking/Internal/StateManager.cs
@@ -996,6 +996,11 @@ public virtual void CascadeDelete(InternalEntityEntry entry, bool force, IEnumer
foreach (InternalEntityEntry dependent in (GetDependentsFromNavigation(entry, fk)
?? GetDependents(entry, fk)).ToList())
{
+ if (dependent.SharedIdentityEntry == entry)
+ {
+ continue;
+ }
+
changeDetector?.DetectChanges(dependent);
if (dependent.EntityState != EntityState.Deleted
diff --git a/src/EFCore/Extensions/ForeignKeyExtensions.cs b/src/EFCore/Extensions/ForeignKeyExtensions.cs
index 1f20728ecc1..55d20168044 100644
--- a/src/EFCore/Extensions/ForeignKeyExtensions.cs
+++ b/src/EFCore/Extensions/ForeignKeyExtensions.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using System.Linq;
using System.Text;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.ChangeTracking;
@@ -71,6 +72,18 @@ public static IEntityType GetRelatedEntityType([NotNull] this IForeignKey foreig
public static INavigation GetNavigation([NotNull] this IForeignKey foreignKey, bool pointsToPrincipal)
=> pointsToPrincipal ? foreignKey.DependentToPrincipal : foreignKey.PrincipalToDependent;
+ ///
+ /// Returns a value indicating whether the foreign key is defined on the primary key and pointing to the same primary key.
+ ///
+ /// The foreign key.
+ /// A value indicating whether the foreign key is defined on the primary key and pointing to the same primary key.
+ public static bool IsBaseLinking([NotNull] this IForeignKey foreignKey)
+ {
+ var primaryKey = foreignKey.DeclaringEntityType.FindPrimaryKey();
+ return primaryKey == foreignKey.PrincipalKey
+ && foreignKey.Properties.SequenceEqual(primaryKey.Properties);
+ }
+
///
///
/// Creates a human-readable representation of the given metadata.
diff --git a/src/EFCore/Infrastructure/ModelValidator.cs b/src/EFCore/Infrastructure/ModelValidator.cs
index c44f1b761e0..415669c088a 100644
--- a/src/EFCore/Infrastructure/ModelValidator.cs
+++ b/src/EFCore/Infrastructure/ModelValidator.cs
@@ -477,7 +477,7 @@ protected virtual void ValidateNoCycles(
var principalType = foreignKey.PrincipalEntityType;
if (!foreignKey.PrincipalKey.IsPrimaryKey()
|| !unvalidatedEntityTypes.Contains(principalType)
- || foreignKey.PrincipalEntityType == entityType
+ || foreignKey.PrincipalEntityType.IsAssignableFrom(entityType)
|| !PropertyListComparer.Instance.Equals(foreignKey.Properties, primaryKey.Properties))
{
continue;
@@ -770,12 +770,13 @@ protected virtual void ValidateForeignKeys(
foreach (var declaredForeignKey in entityType.GetDeclaredForeignKeys())
{
if (declaredForeignKey.PrincipalEntityType == declaredForeignKey.DeclaringEntityType
- && PropertyListComparer.Instance.Equals(declaredForeignKey.PrincipalKey.Properties, declaredForeignKey.Properties))
+ && declaredForeignKey.PrincipalKey.Properties.SequenceEqual(declaredForeignKey.Properties))
{
logger.RedundantForeignKeyWarning(declaredForeignKey);
}
- if (entityType.BaseType == null)
+ if (entityType.BaseType == null
+ || declaredForeignKey.IsBaseLinking())
{
continue;
}
diff --git a/src/EFCore/Metadata/Conventions/ForeignKeyPropertyDiscoveryConvention.cs b/src/EFCore/Metadata/Conventions/ForeignKeyPropertyDiscoveryConvention.cs
index cad68e9eda2..65437509dda 100644
--- a/src/EFCore/Metadata/Conventions/ForeignKeyPropertyDiscoveryConvention.cs
+++ b/src/EFCore/Metadata/Conventions/ForeignKeyPropertyDiscoveryConvention.cs
@@ -157,7 +157,9 @@ private IConventionForeignKeyBuilder DiscoverProperties(
|| foreignKey.DeclaringEntityType.IsKeyless
|| (!foreignKey.IsUnique && !ConfigurationSource.Convention.Overrides(foreignKey.GetIsUniqueConfigurationSource()))
|| foreignKey.PrincipalToDependent?.IsCollection == true
- || foreignKey.DeclaringEntityType.FindOwnership() != null)
+ || foreignKey.DeclaringEntityType.FindOwnership() != null
+ || (foreignKey.IsBaseLinking()
+ && foreignKey.PrincipalEntityType.IsAssignableFrom(foreignKey.DeclaringEntityType)))
{
relationshipBuilder = relationshipBuilder.HasEntityTypes(
foreignKey.PrincipalEntityType, foreignKey.DeclaringEntityType);
diff --git a/src/EFCore/Metadata/Conventions/ValueGenerationConvention.cs b/src/EFCore/Metadata/Conventions/ValueGenerationConvention.cs
index f24a0977ead..d6225e10c40 100644
--- a/src/EFCore/Metadata/Conventions/ValueGenerationConvention.cs
+++ b/src/EFCore/Metadata/Conventions/ValueGenerationConvention.cs
@@ -44,9 +44,13 @@ public ValueGenerationConvention([NotNull] ProviderConventionSetBuilderDependenc
public virtual void ProcessForeignKeyAdded(
IConventionForeignKeyBuilder relationshipBuilder, IConventionContext context)
{
- foreach (var property in relationshipBuilder.Metadata.Properties)
+ var foreignKey = relationshipBuilder.Metadata;
+ if (!foreignKey.IsBaseLinking())
{
- property.Builder.ValueGenerated(ValueGenerated.Never);
+ foreach (var property in foreignKey.Properties)
+ {
+ property.Builder.ValueGenerated(ValueGenerated.Never);
+ }
}
}
@@ -82,7 +86,8 @@ public virtual void ProcessForeignKeyPropertiesChanged(
{
OnForeignKeyRemoved(oldDependentProperties);
- if (relationshipBuilder.Metadata.Builder != null)
+ if (relationshipBuilder.Metadata.Builder != null
+ && !foreignKey.IsBaseLinking())
{
foreach (var property in foreignKey.Properties)
{
@@ -179,7 +184,7 @@ public virtual void ProcessEntityTypeBaseTypeChanged(
/// The property.
/// The store value generation strategy to set for the given property.
public static ValueGenerated? GetValueGenerated([NotNull] IProperty property)
- => !property.IsForeignKey()
+ => !property.GetContainingForeignKeys().Any(fk => !fk.IsBaseLinking())
&& ShouldHaveGeneratedProperty(property.FindContainingPrimaryKey())
&& CanBeGenerated(property)
? ValueGenerated.OnAdd
diff --git a/src/EFCore/Metadata/Internal/ForeignKeyExtensions.cs b/src/EFCore/Metadata/Internal/ForeignKeyExtensions.cs
index ba5878e1273..c5f29421dda 100644
--- a/src/EFCore/Metadata/Internal/ForeignKeyExtensions.cs
+++ b/src/EFCore/Metadata/Internal/ForeignKeyExtensions.cs
@@ -27,15 +27,6 @@ public static class ForeignKeyExtensions
public static bool IsSelfReferencing([NotNull] this IForeignKey foreignKey)
=> foreignKey.DeclaringEntityType == foreignKey.PrincipalEntityType;
- ///
- /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
- /// the same compatibility standards as public APIs. It may be changed or removed without notice in
- /// any release. You should only use it directly in your code with extreme caution and knowing that
- /// doing so can result in application failures when updating to a new Entity Framework Core release.
- ///
- public static bool IsSelfPrimaryKeyReferencing([NotNull] this IForeignKey foreignKey)
- => foreignKey.DeclaringEntityType.FindPrimaryKey() == foreignKey.PrincipalKey;
-
///
/// 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 6970c00af11..b1f0c819313 100644
--- a/src/EFCore/Metadata/Internal/InternalEntityTypeBuilder.cs
+++ b/src/EFCore/Metadata/Internal/InternalEntityTypeBuilder.cs
@@ -2796,7 +2796,7 @@ private InternalForeignKeyBuilder HasRelationship(
principalKey: null,
propertyBaseName: navigationProperty?.GetSimpleMemberName(),
required: required,
- configurationSource: configurationSource);
+ configurationSource);
}
else
{
@@ -2812,7 +2812,7 @@ private InternalForeignKeyBuilder HasRelationship(
principalKey: null,
propertyBaseName: navigationProperty?.GetSimpleMemberName(),
required: null,
- configurationSource: configurationSource);
+ configurationSource);
}
relationship = newRelationship;
@@ -3884,8 +3884,8 @@ private IReadOnlyList CreateUniqueProperties(
using var principalPropertyTypesEnumerator = principalPropertyTypes.GetEnumerator();
for (var i = 0;
i < propertyCount
- && principalPropertyNamesEnumerator.MoveNext()
- && principalPropertyTypesEnumerator.MoveNext();
+ && principalPropertyNamesEnumerator.MoveNext()
+ && principalPropertyTypesEnumerator.MoveNext();
i++)
{
var keyPropertyName = principalPropertyNamesEnumerator.Current;
diff --git a/src/EFCore/Metadata/Internal/InternalForeignKeyBuilder.cs b/src/EFCore/Metadata/Internal/InternalForeignKeyBuilder.cs
index f20f358e7f0..d36f5065a4c 100644
--- a/src/EFCore/Metadata/Internal/InternalForeignKeyBuilder.cs
+++ b/src/EFCore/Metadata/Internal/InternalForeignKeyBuilder.cs
@@ -1894,6 +1894,7 @@ private bool CanSetForeignKey(
// FKs are not allowed to use properties from inherited keys since this could result in an ambiguous value space
if (dependentEntityType.BaseType != null
+ && !principalEntityType.IsAssignableFrom(dependentEntityType)
&& configurationSource != ConfigurationSource.Explicit // let it throw for explicit
&& properties.Any(p => p.GetContainingKeys().Any(k => k.DeclaringEntityType != dependentEntityType)))
{
diff --git a/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs b/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs
index ec2f8c2022d..005bf8fdbc5 100644
--- a/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs
+++ b/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs
@@ -416,6 +416,15 @@ public virtual void Entities_are_stored_in_model_snapshot_for_TPT()
.HasColumnType(""nvarchar(max)"");
b.ToTable(""DerivedEntity"", ""foo"");
+ });
+
+ modelBuilder.Entity(""Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+DerivedEntity"", b =>
+ {
+ b.HasOne(""Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+BaseEntity"", null)
+ .WithOne()
+ .HasForeignKey(""Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+DerivedEntity"", ""Id"")
+ .OnDelete(DeleteBehavior.ClientCascade)
+ .IsRequired();
});"),
o =>
{
@@ -462,6 +471,15 @@ public virtual void Entities_are_stored_in_model_snapshot_for_TPT_with_one_exclu
.HasColumnType(""nvarchar(max)"");
b.ToTable(""DerivedEntity"", ""foo"", t => t.ExcludeFromMigrations());
+ });
+
+ modelBuilder.Entity(""Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+DerivedEntity"", b =>
+ {
+ b.HasOne(""Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+BaseEntity"", null)
+ .WithOne()
+ .HasForeignKey(""Microsoft.EntityFrameworkCore.Migrations.ModelSnapshotSqlServerTest+DerivedEntity"", ""Id"")
+ .OnDelete(DeleteBehavior.ClientCascade)
+ .IsRequired();
});"),
o =>
{
diff --git a/test/EFCore.Relational.Specification.Tests/TPTTableSplittingTestBase.cs b/test/EFCore.Relational.Specification.Tests/TPTTableSplittingTestBase.cs
index ccaadd37d44..37eb79a5e4f 100644
--- a/test/EFCore.Relational.Specification.Tests/TPTTableSplittingTestBase.cs
+++ b/test/EFCore.Relational.Specification.Tests/TPTTableSplittingTestBase.cs
@@ -26,20 +26,45 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
modelBuilder.Entity().ToTable("Vehicles");
modelBuilder.Entity().ToTable("PoweredVehicles");
- modelBuilder.Entity().ToTable("Vehicles");
+ modelBuilder.Entity(
+ eb =>
+ {
+ eb.ToTable("Vehicles");
+ eb.HasOne(e => e.Vehicle)
+ .WithOne(e => e.Operator)
+ .HasForeignKey(e => e.VehicleName)
+ .OnDelete(DeleteBehavior.ClientCascade);
+ eb.HasOne(e => e.Details)
+ .WithOne()
+ .HasForeignKey(e => e.VehicleName)
+ .OnDelete(DeleteBehavior.ClientCascade);
+ });
+
modelBuilder.Entity().ToTable("LicensedOperators");
modelBuilder.Entity().ToTable("Vehicles");
modelBuilder.Entity().ToTable("PoweredVehicles")
- .HasOne(e => e.Vehicle).WithOne(e => e.Engine).OnDelete(DeleteBehavior.NoAction);
+ .HasOne(e => e.Vehicle).WithOne(e => e.Engine).OnDelete(DeleteBehavior.ClientCascade);
modelBuilder.Entity().ToTable("CombustionEngines");
modelBuilder.Entity().ToTable("IntermittentCombustionEngines");
modelBuilder.Entity().ToTable("ContinuousCombustionEngines");
modelBuilder.Entity().ToTable("SolidRockets").Ignore(e => e.SolidFuelTank);
- modelBuilder.Entity().ToTable("CombustionEngines")
- .HasOne(e => e.Vehicle).WithOne().OnDelete(DeleteBehavior.NoAction);
+ modelBuilder.Entity(
+ eb =>
+ {
+ eb.ToTable("CombustionEngines");
+
+ eb.HasOne(e => e.Engine)
+ .WithOne(e => e.FuelTank)
+ .HasForeignKey(e => e.VehicleName)
+ .OnDelete(DeleteBehavior.ClientCascade);
+ eb.HasOne(e => e.Vehicle)
+ .WithOne()
+ .HasForeignKey(e => e.VehicleName)
+ .OnDelete(DeleteBehavior.ClientCascade);
+ });
modelBuilder.Entity().ToTable("SolidFuelTanks").Ignore(e => e.Rocket);
}
}
diff --git a/test/EFCore.Relational.Specification.Tests/TableSplittingTestBase.cs b/test/EFCore.Relational.Specification.Tests/TableSplittingTestBase.cs
index 314b988e82f..fc23608057f 100644
--- a/test/EFCore.Relational.Specification.Tests/TableSplittingTestBase.cs
+++ b/test/EFCore.Relational.Specification.Tests/TableSplittingTestBase.cs
@@ -346,7 +346,8 @@ public virtual void Can_manipulate_entities_sharing_row_independently()
using (var context = CreateContext())
{
- var streetcarFromStore = context.Set().Include(v => v.Engine).AsNoTracking()
+ var streetcarFromStore = context.Set().AsNoTracking()
+ .Include(v => v.Engine).Include(v => v.Operator)
.Single(v => v.Name == "1984 California Car");
Assert.Null(streetcarFromStore.Engine);
diff --git a/test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs b/test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs
index b63040de965..17d00cb0351 100644
--- a/test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs
+++ b/test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs
@@ -435,12 +435,19 @@ private static void AssertTables(IRelationalModel model, Mapping mapping)
Assert.Equal("AK_Customer_SpecialityAk", specialCustomerUniqueConstraint.Name);
Assert.NotNull(specialCustomerUniqueConstraint.MappedKeys.Single());
- var specialCustomerFkConstraint = specialCustomerTable.ForeignKeyConstraints.First();
+ var foreignKeys = specialCustomerTable.ForeignKeyConstraints.ToArray();
+
+ var specialCustomerTptFkConstraint = foreignKeys[0];
+ Assert.Equal("FK_SpecialCustomer_Customer_Id", specialCustomerTptFkConstraint.Name);
+ Assert.NotNull(specialCustomerTptFkConstraint.MappedForeignKeys.Single());
+ Assert.Same(customerTable, specialCustomerTptFkConstraint.PrincipalTable);
+
+ var specialCustomerFkConstraint = foreignKeys[1];
Assert.Equal("FK_SpecialCustomer_Customer_RelatedCustomerSpeciality", specialCustomerFkConstraint.Name);
Assert.NotNull(specialCustomerFkConstraint.MappedForeignKeys.Single());
Assert.Same(customerTable, specialCustomerFkConstraint.PrincipalTable);
- var anotherSpecialCustomerFkConstraint = specialCustomerTable.ForeignKeyConstraints.Last();
+ var anotherSpecialCustomerFkConstraint = foreignKeys[2];
Assert.Equal("FK_SpecialCustomer_SpecialCustomer_AnotherRelatedCustomerId", anotherSpecialCustomerFkConstraint.Name);
Assert.NotNull(anotherSpecialCustomerFkConstraint.MappedForeignKeys.Single());
Assert.Same(specialCustomerTable, anotherSpecialCustomerFkConstraint.PrincipalTable);
diff --git a/test/EFCore.Relational.Tests/Migrations/Internal/MigrationsModelDifferTest.cs b/test/EFCore.Relational.Tests/Migrations/Internal/MigrationsModelDifferTest.cs
index 545a6888617..6537804e70a 100644
--- a/test/EFCore.Relational.Tests/Migrations/Internal/MigrationsModelDifferTest.cs
+++ b/test/EFCore.Relational.Tests/Migrations/Internal/MigrationsModelDifferTest.cs
@@ -5316,6 +5316,8 @@ public void Change_TPH_to_TPT_with_FKs_and_seed_data()
"Dog", x =>
{
x.ToTable("Dogs");
+ x.HasOne("Animal", null).WithOne().HasForeignKey("Dog", "Id")
+ .HasConstraintName("FK_Dogs_Animal");
x.HasData(
new { Id = 22, PreyId = 33 },
new { Id = 23 });
@@ -5419,13 +5421,24 @@ public void Change_TPH_to_TPT_with_FKs_and_seed_data()
Assert.Equal("Cats", pk.Table);
Assert.Equal(new[] { "Id" }, pk.Columns);
- var fk = operation.ForeignKeys.Single();
- Assert.Equal("FK_Cats_Animal_PreyId", fk.Name);
- Assert.Equal("Cats", fk.Table);
- Assert.Equal("Animal", fk.PrincipalTable);
- Assert.Equal(new[] { "PreyId" }, fk.Columns);
- Assert.Equal(new[] { "Id" }, fk.PrincipalColumns);
- Assert.Equal(ReferentialAction.Restrict, fk.OnDelete);
+ Assert.Collection(operation.ForeignKeys,
+ fk => {
+ Assert.Equal("FK_Cats_Animal_Id", fk.Name);
+ Assert.Equal("Cats", fk.Table);
+ Assert.Equal("Animal", fk.PrincipalTable);
+ Assert.Equal(new[] { "Id" }, fk.Columns);
+ Assert.Equal(new[] { "Id" }, fk.PrincipalColumns);
+ Assert.Equal(ReferentialAction.Cascade, fk.OnDelete);
+ },
+ fk =>
+ {
+ Assert.Equal("FK_Cats_Animal_PreyId", fk.Name);
+ Assert.Equal("Cats", fk.Table);
+ Assert.Equal("Animal", fk.PrincipalTable);
+ Assert.Equal(new[] { "PreyId" }, fk.Columns);
+ Assert.Equal(new[] { "Id" }, fk.PrincipalColumns);
+ Assert.Equal(ReferentialAction.Restrict, fk.OnDelete);
+ });
Assert.Empty(operation.UniqueConstraints);
Assert.Null(operation.Comment);
@@ -5461,7 +5474,14 @@ public void Change_TPH_to_TPT_with_FKs_and_seed_data()
Assert.Equal("Mice", pk.Table);
Assert.Equal(new[] { "Id" }, pk.Columns);
- Assert.Empty(operation.ForeignKeys);
+ var fk = operation.ForeignKeys.Single();
+ Assert.Equal("FK_Mice_Animal_Id", fk.Name);
+ Assert.Equal("Mice", fk.Table);
+ Assert.Equal("Animal", fk.PrincipalTable);
+ Assert.Equal(new[] { "Id" }, fk.Columns);
+ Assert.Equal(new[] { "Id" }, fk.PrincipalColumns);
+ Assert.Equal(ReferentialAction.Cascade, fk.OnDelete);
+
Assert.Empty(operation.UniqueConstraints);
Assert.Null(operation.Comment);
Assert.Empty(operation.CheckConstraints);
@@ -5534,31 +5554,31 @@ public void Change_TPH_to_TPT_with_FKs_and_seed_data()
{
var operation = Assert.IsType(o);
Assert.Equal("Dogs", operation.Table);
+
Assert.Equal(new[] { "Id", "PreyId" }, operation.Columns);
+ Assert.Null(operation.ColumnTypes);
AssertMultidimensionalArray(
operation.Values,
- v => Assert.Equal(23, v),
- v => Assert.Null(v));
+ v => Assert.Equal(22, v),
+ v => Assert.Equal(33, v));
},
o =>
{
var operation = Assert.IsType(o);
- Assert.Equal("Mice", operation.Table);
- Assert.Equal(new[] { "Id" }, operation.Columns);
+ Assert.Equal("Dogs", operation.Table);
+ Assert.Equal(new[] { "Id", "PreyId" }, operation.Columns);
AssertMultidimensionalArray(
operation.Values,
- v => Assert.Equal(33, v));
+ v => Assert.Equal(23, v),
+ v => Assert.Null(v));
},
o =>
{
var operation = Assert.IsType(o);
- Assert.Equal("Dogs", operation.Table);
-
- Assert.Equal(new[] { "Id", "PreyId" }, operation.Columns);
- Assert.Null(operation.ColumnTypes);
+ Assert.Equal("Mice", operation.Table);
+ Assert.Equal(new[] { "Id" }, operation.Columns);
AssertMultidimensionalArray(
operation.Values,
- v => Assert.Equal(22, v),
v => Assert.Equal(33, v));
},
o =>
@@ -5586,6 +5606,16 @@ public void Change_TPH_to_TPT_with_FKs_and_seed_data()
Assert.Equal(ReferentialAction.Restrict, operation.OnDelete);
},
o =>
+ {
+ var operation = Assert.IsType(o);
+ Assert.Equal("FK_Dogs_Animal", operation.Name);
+ Assert.Equal("Dogs", operation.Table);
+ Assert.Equal("Animal", operation.PrincipalTable);
+ Assert.Equal(new[] { "Id" }, operation.Columns);
+ Assert.Equal(new[] { "Id" }, operation.PrincipalColumns);
+ Assert.Equal(ReferentialAction.Cascade, operation.OnDelete);
+ },
+ o =>
{
var operation = Assert.IsType(o);
Assert.Equal("FK_Dogs_Animal_PreyId", operation.Name);
@@ -5604,6 +5634,12 @@ public void Change_TPH_to_TPT_with_FKs_and_seed_data()
Assert.Equal("Animal", operation.Table);
},
o =>
+ {
+ var operation = Assert.IsType(o);
+ Assert.Equal("FK_Dogs_Animal", operation.Name);
+ Assert.Equal("Dogs", operation.Table);
+ },
+ o =>
{
var operation = Assert.IsType(o);
Assert.Equal("FK_Dogs_Animal_PreyId", operation.Name);
@@ -6017,13 +6053,24 @@ public void Change_TPH_to_TPT_with_FKs_and_seed_data_readonly_discriminator()
Assert.Equal("Cats", pk.Table);
Assert.Equal(new[] { "Id" }, pk.Columns);
- var fk = operation.ForeignKeys.Single();
- Assert.Equal("FK_Cats_Animal_PreyId", fk.Name);
- Assert.Equal("Cats", fk.Table);
- Assert.Equal("Animal", fk.PrincipalTable);
- Assert.Equal(new[] { "PreyId" }, fk.Columns);
- Assert.Equal(new[] { "Id" }, fk.PrincipalColumns);
- Assert.Equal(ReferentialAction.Restrict, fk.OnDelete);
+ Assert.Collection(operation.ForeignKeys,
+ fk => {
+ Assert.Equal("FK_Cats_Animal_Id", fk.Name);
+ Assert.Equal("Cats", fk.Table);
+ Assert.Equal("Animal", fk.PrincipalTable);
+ Assert.Equal(new[] { "Id" }, fk.Columns);
+ Assert.Equal(new[] { "Id" }, fk.PrincipalColumns);
+ Assert.Equal(ReferentialAction.Cascade, fk.OnDelete);
+ },
+ fk =>
+ {
+ Assert.Equal("FK_Cats_Animal_PreyId", fk.Name);
+ Assert.Equal("Cats", fk.Table);
+ Assert.Equal("Animal", fk.PrincipalTable);
+ Assert.Equal(new[] { "PreyId" }, fk.Columns);
+ Assert.Equal(new[] { "Id" }, fk.PrincipalColumns);
+ Assert.Equal(ReferentialAction.Restrict, fk.OnDelete);
+ });
Assert.Empty(operation.UniqueConstraints);
Assert.Null(operation.Comment);
@@ -6059,7 +6106,14 @@ public void Change_TPH_to_TPT_with_FKs_and_seed_data_readonly_discriminator()
Assert.Equal("Mice", pk.Table);
Assert.Equal(new[] { "Id" }, pk.Columns);
- Assert.Empty(operation.ForeignKeys);
+ var fk = operation.ForeignKeys.Single();
+ Assert.Equal("FK_Mice_Animal_Id", fk.Name);
+ Assert.Equal("Mice", fk.Table);
+ Assert.Equal("Animal", fk.PrincipalTable);
+ Assert.Equal(new[] { "Id" }, fk.Columns);
+ Assert.Equal(new[] { "Id" }, fk.PrincipalColumns);
+ Assert.Equal(ReferentialAction.Cascade, fk.OnDelete);
+
Assert.Empty(operation.UniqueConstraints);
Assert.Null(operation.Comment);
Assert.Empty(operation.CheckConstraints);
@@ -6132,31 +6186,31 @@ public void Change_TPH_to_TPT_with_FKs_and_seed_data_readonly_discriminator()
{
var operation = Assert.IsType(o);
Assert.Equal("Dogs", operation.Table);
+
Assert.Equal(new[] { "Id", "PreyId" }, operation.Columns);
+ Assert.Null(operation.ColumnTypes);
AssertMultidimensionalArray(
operation.Values,
- v => Assert.Equal(23, v),
- v => Assert.Null(v));
+ v => Assert.Equal(22, v),
+ v => Assert.Equal(33, v));
},
o =>
{
var operation = Assert.IsType(o);
- Assert.Equal("Mice", operation.Table);
- Assert.Equal(new[] { "Id" }, operation.Columns);
+ Assert.Equal("Dogs", operation.Table);
+ Assert.Equal(new[] { "Id", "PreyId" }, operation.Columns);
AssertMultidimensionalArray(
operation.Values,
- v => Assert.Equal(33, v));
+ v => Assert.Equal(23, v),
+ v => Assert.Null(v));
},
o =>
{
var operation = Assert.IsType(o);
- Assert.Equal("Dogs", operation.Table);
-
- Assert.Equal(new[] { "Id", "PreyId" }, operation.Columns);
- Assert.Null(operation.ColumnTypes);
+ Assert.Equal("Mice", operation.Table);
+ Assert.Equal(new[] { "Id" }, operation.Columns);
AssertMultidimensionalArray(
operation.Values,
- v => Assert.Equal(22, v),
v => Assert.Equal(33, v));
},
o =>
@@ -6184,6 +6238,16 @@ public void Change_TPH_to_TPT_with_FKs_and_seed_data_readonly_discriminator()
Assert.Equal(ReferentialAction.Restrict, operation.OnDelete);
},
o =>
+ {
+ var operation = Assert.IsType(o);
+ Assert.Equal("FK_Dogs_Animal_Id", operation.Name);
+ Assert.Equal("Dogs", operation.Table);
+ Assert.Equal("Animal", operation.PrincipalTable);
+ Assert.Equal(new[] { "Id" }, operation.Columns);
+ Assert.Equal(new[] { "Id" }, operation.PrincipalColumns);
+ Assert.Equal(ReferentialAction.Cascade, operation.OnDelete);
+ },
+ o =>
{
var operation = Assert.IsType(o);
Assert.Equal("FK_Dogs_Animal_PreyId", operation.Name);
@@ -6202,6 +6266,12 @@ public void Change_TPH_to_TPT_with_FKs_and_seed_data_readonly_discriminator()
Assert.Equal("Animal", operation.Table);
},
o =>
+ {
+ var operation = Assert.IsType(o);
+ Assert.Equal("FK_Dogs_Animal_Id", operation.Name);
+ Assert.Equal("Dogs", operation.Table);
+ },
+ o =>
{
var operation = Assert.IsType(o);
Assert.Equal("FK_Dogs_Animal_PreyId", operation.Name);
diff --git a/test/EFCore.Specification.Tests/Query/InheritanceRelationshipsQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/InheritanceRelationshipsQueryTestBase.cs
index 3a2cd126e76..3aac06616a6 100644
--- a/test/EFCore.Specification.Tests/Query/InheritanceRelationshipsQueryTestBase.cs
+++ b/test/EFCore.Specification.Tests/Query/InheritanceRelationshipsQueryTestBase.cs
@@ -68,7 +68,7 @@ public virtual void Entity_can_make_separate_relationships_with_base_type_and_de
Assert.Equal(nameof(BaseReferenceOnDerived.BaseParent), fkOnBase.DependentToPrincipal.Name);
Assert.Equal(nameof(DerivedInheritanceRelationshipEntity.BaseReferenceOnDerived), fkOnBase.PrincipalToDependent.Name);
- var fkOnDerived = derivedDependentEntityType.GetDeclaredForeignKeys().Single();
+ var fkOnDerived = derivedDependentEntityType.GetDeclaredForeignKeys().Single(fk => fk.PrincipalEntityType != dependentEntityType);
Assert.NotSame(fkOnBase, fkOnDerived);
Assert.Equal(principalEntityType, fkOnDerived.PrincipalEntityType);
Assert.Equal(derivedDependentEntityType, fkOnDerived.DeclaringEntityType);
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/OwnedQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/OwnedQuerySqlServerTest.cs
index 8ac619c670c..6e25ff0eadb 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/OwnedQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/OwnedQuerySqlServerTest.cs
@@ -949,7 +949,7 @@ public override async Task Using_from_sql_on_owner_generates_join_with_table_for
await base.Using_from_sql_on_owner_generates_join_with_table_for_owned_shared_dependents(async);
AssertSql(
- @"SELECT [o].[Id], [o].[Discriminator], [o].[Name], [t].[Id], [t].[PersonAddress_AddressLine], [t].[PersonAddress_PlaceType], [t].[PersonAddress_ZipCode], [t].[Id1], [t].[PersonAddress_Country_Name], [t].[PersonAddress_Country_PlanetId], [t3].[Id], [t3].[BranchAddress_BranchName], [t3].[BranchAddress_PlaceType], [t8].[Id], [t8].[BranchAddress_Country_Name], [t8].[BranchAddress_Country_PlanetId], [t12].[Id], [t12].[LeafBAddress_LeafBType], [t12].[LeafBAddress_PlaceType], [t17].[Id], [t17].[LeafBAddress_Country_Name], [t17].[LeafBAddress_Country_PlanetId], [t19].[Id], [t19].[LeafAAddress_LeafType], [t19].[LeafAAddress_PlaceType], [t19].[Id1], [t19].[LeafAAddress_Country_Name], [t19].[LeafAAddress_Country_PlanetId], [t].[Id0], [t3].[Id0], [t8].[Id0], [t8].[Id00], [t12].[Id0], [t17].[Id0], [t17].[Id00], [t19].[Id0], [o22].[ClientId], [o22].[Id], [o22].[OrderDate]
+ @"SELECT [o].[Id], [o].[Discriminator], [o].[Name], [t].[Id], [t].[PersonAddress_AddressLine], [t].[PersonAddress_PlaceType], [t].[PersonAddress_ZipCode], [t].[Id1], [t].[PersonAddress_Country_Name], [t].[PersonAddress_Country_PlanetId], [t1].[Id], [t1].[BranchAddress_BranchName], [t1].[BranchAddress_PlaceType], [t1].[Id1], [t1].[BranchAddress_Country_Name], [t1].[BranchAddress_Country_PlanetId], [t3].[Id], [t3].[LeafBAddress_LeafBType], [t3].[LeafBAddress_PlaceType], [t3].[Id1], [t3].[LeafBAddress_Country_Name], [t3].[LeafBAddress_Country_PlanetId], [t5].[Id], [t5].[LeafAAddress_LeafType], [t5].[LeafAAddress_PlaceType], [t5].[Id1], [t5].[LeafAAddress_Country_Name], [t5].[LeafAAddress_Country_PlanetId], [t].[Id0], [t1].[Id0], [t3].[Id0], [t5].[Id0], [o8].[ClientId], [o8].[Id], [o8].[OrderDate]
FROM (
SELECT * FROM ""OwnedPerson""
) AS [o]
@@ -960,111 +960,37 @@ FROM [OwnedPerson] AS [o0]
WHERE [o0].[PersonAddress_ZipCode] IS NOT NULL
) AS [t] ON [o].[Id] = [t].[Id]
LEFT JOIN (
- SELECT [t1].[Id], [t1].[BranchAddress_BranchName], [t1].[BranchAddress_PlaceType], [t2].[Id] AS [Id0]
- FROM (
- SELECT [o2].[Id], [o2].[BranchAddress_BranchName], [o2].[BranchAddress_PlaceType]
- FROM [OwnedPerson] AS [o2]
- WHERE [o2].[BranchAddress_PlaceType] IS NOT NULL OR [o2].[BranchAddress_BranchName] IS NOT NULL
- UNION
- SELECT [o3].[Id], [o3].[BranchAddress_BranchName], [o3].[BranchAddress_PlaceType]
+ SELECT [o2].[Id], [o2].[BranchAddress_BranchName], [o2].[BranchAddress_PlaceType], [t0].[Id] AS [Id0], [o2].[Id] AS [Id1], [o2].[BranchAddress_Country_Name], [o2].[BranchAddress_Country_PlanetId]
+ FROM [OwnedPerson] AS [o2]
+ INNER JOIN (
+ SELECT [o3].[Id]
FROM [OwnedPerson] AS [o3]
- INNER JOIN (
- SELECT [o4].[Id], [o4].[BranchAddress_Country_Name], [o4].[BranchAddress_Country_PlanetId]
- FROM [OwnedPerson] AS [o4]
- WHERE [o4].[BranchAddress_Country_PlanetId] IS NOT NULL
- ) AS [t0] ON [o3].[Id] = [t0].[Id]
- ) AS [t1]
+ WHERE [o3].[Discriminator] IN (N'Branch', N'LeafA')
+ ) AS [t0] ON [o2].[Id] = [t0].[Id]
+ WHERE [o2].[BranchAddress_PlaceType] IS NOT NULL OR [o2].[BranchAddress_BranchName] IS NOT NULL
+) AS [t1] ON [o].[Id] = [t1].[Id]
+LEFT JOIN (
+ SELECT [o4].[Id], [o4].[LeafBAddress_LeafBType], [o4].[LeafBAddress_PlaceType], [t2].[Id] AS [Id0], [o4].[Id] AS [Id1], [o4].[LeafBAddress_Country_Name], [o4].[LeafBAddress_Country_PlanetId]
+ FROM [OwnedPerson] AS [o4]
INNER JOIN (
SELECT [o5].[Id]
FROM [OwnedPerson] AS [o5]
- WHERE [o5].[Discriminator] IN (N'Branch', N'LeafA')
- ) AS [t2] ON [t1].[Id] = [t2].[Id]
+ WHERE [o5].[Discriminator] = N'LeafB'
+ ) AS [t2] ON [o4].[Id] = [t2].[Id]
+ WHERE [o4].[LeafBAddress_PlaceType] IS NOT NULL OR [o4].[LeafBAddress_LeafBType] IS NOT NULL
) AS [t3] ON [o].[Id] = [t3].[Id]
LEFT JOIN (
- SELECT [o6].[Id], [o6].[BranchAddress_Country_Name], [o6].[BranchAddress_Country_PlanetId], [t7].[Id] AS [Id0], [t7].[Id0] AS [Id00]
+ SELECT [o6].[Id], [o6].[LeafAAddress_LeafType], [o6].[LeafAAddress_PlaceType], [t4].[Id] AS [Id0], [o6].[Id] AS [Id1], [o6].[LeafAAddress_Country_Name], [o6].[LeafAAddress_Country_PlanetId]
FROM [OwnedPerson] AS [o6]
INNER JOIN (
- SELECT [t5].[Id], [t6].[Id] AS [Id0]
- FROM (
- SELECT [o7].[Id], [o7].[BranchAddress_BranchName], [o7].[BranchAddress_PlaceType]
- FROM [OwnedPerson] AS [o7]
- WHERE [o7].[BranchAddress_PlaceType] IS NOT NULL OR [o7].[BranchAddress_BranchName] IS NOT NULL
- UNION
- SELECT [o8].[Id], [o8].[BranchAddress_BranchName], [o8].[BranchAddress_PlaceType]
- FROM [OwnedPerson] AS [o8]
- INNER JOIN (
- SELECT [o9].[Id], [o9].[BranchAddress_Country_Name], [o9].[BranchAddress_Country_PlanetId]
- FROM [OwnedPerson] AS [o9]
- WHERE [o9].[BranchAddress_Country_PlanetId] IS NOT NULL
- ) AS [t4] ON [o8].[Id] = [t4].[Id]
- ) AS [t5]
- INNER JOIN (
- SELECT [o10].[Id]
- FROM [OwnedPerson] AS [o10]
- WHERE [o10].[Discriminator] IN (N'Branch', N'LeafA')
- ) AS [t6] ON [t5].[Id] = [t6].[Id]
- ) AS [t7] ON [o6].[Id] = [t7].[Id]
- WHERE [o6].[BranchAddress_Country_PlanetId] IS NOT NULL
-) AS [t8] ON [t3].[Id] = [t8].[Id]
-LEFT JOIN (
- SELECT [t10].[Id], [t10].[LeafBAddress_LeafBType], [t10].[LeafBAddress_PlaceType], [t11].[Id] AS [Id0]
- FROM (
- SELECT [o11].[Id], [o11].[LeafBAddress_LeafBType], [o11].[LeafBAddress_PlaceType]
- FROM [OwnedPerson] AS [o11]
- WHERE [o11].[LeafBAddress_PlaceType] IS NOT NULL OR [o11].[LeafBAddress_LeafBType] IS NOT NULL
- UNION
- SELECT [o12].[Id], [o12].[LeafBAddress_LeafBType], [o12].[LeafBAddress_PlaceType]
- FROM [OwnedPerson] AS [o12]
- INNER JOIN (
- SELECT [o13].[Id], [o13].[LeafBAddress_Country_Name], [o13].[LeafBAddress_Country_PlanetId]
- FROM [OwnedPerson] AS [o13]
- WHERE [o13].[LeafBAddress_Country_PlanetId] IS NOT NULL
- ) AS [t9] ON [o12].[Id] = [t9].[Id]
- ) AS [t10]
- INNER JOIN (
- SELECT [o14].[Id]
- FROM [OwnedPerson] AS [o14]
- WHERE [o14].[Discriminator] = N'LeafB'
- ) AS [t11] ON [t10].[Id] = [t11].[Id]
-) AS [t12] ON [o].[Id] = [t12].[Id]
-LEFT JOIN (
- SELECT [o15].[Id], [o15].[LeafBAddress_Country_Name], [o15].[LeafBAddress_Country_PlanetId], [t16].[Id] AS [Id0], [t16].[Id0] AS [Id00]
- FROM [OwnedPerson] AS [o15]
- INNER JOIN (
- SELECT [t14].[Id], [t15].[Id] AS [Id0]
- FROM (
- SELECT [o16].[Id], [o16].[LeafBAddress_LeafBType], [o16].[LeafBAddress_PlaceType]
- FROM [OwnedPerson] AS [o16]
- WHERE [o16].[LeafBAddress_PlaceType] IS NOT NULL OR [o16].[LeafBAddress_LeafBType] IS NOT NULL
- UNION
- SELECT [o17].[Id], [o17].[LeafBAddress_LeafBType], [o17].[LeafBAddress_PlaceType]
- FROM [OwnedPerson] AS [o17]
- INNER JOIN (
- SELECT [o18].[Id], [o18].[LeafBAddress_Country_Name], [o18].[LeafBAddress_Country_PlanetId]
- FROM [OwnedPerson] AS [o18]
- WHERE [o18].[LeafBAddress_Country_PlanetId] IS NOT NULL
- ) AS [t13] ON [o17].[Id] = [t13].[Id]
- ) AS [t14]
- INNER JOIN (
- SELECT [o19].[Id]
- FROM [OwnedPerson] AS [o19]
- WHERE [o19].[Discriminator] = N'LeafB'
- ) AS [t15] ON [t14].[Id] = [t15].[Id]
- ) AS [t16] ON [o15].[Id] = [t16].[Id]
- WHERE [o15].[LeafBAddress_Country_PlanetId] IS NOT NULL
-) AS [t17] ON [t12].[Id] = [t17].[Id]
-LEFT JOIN (
- SELECT [o20].[Id], [o20].[LeafAAddress_LeafType], [o20].[LeafAAddress_PlaceType], [t18].[Id] AS [Id0], [o20].[Id] AS [Id1], [o20].[LeafAAddress_Country_Name], [o20].[LeafAAddress_Country_PlanetId]
- FROM [OwnedPerson] AS [o20]
- INNER JOIN (
- SELECT [o21].[Id]
- FROM [OwnedPerson] AS [o21]
- WHERE [o21].[Discriminator] = N'LeafA'
- ) AS [t18] ON [o20].[Id] = [t18].[Id]
- WHERE [o20].[LeafAAddress_LeafType] IS NOT NULL
-) AS [t19] ON [o].[Id] = [t19].[Id]
-LEFT JOIN [Order] AS [o22] ON [o].[Id] = [o22].[ClientId]
-ORDER BY [o].[Id], [t].[Id], [t].[Id0], [t3].[Id], [t3].[Id0], [t8].[Id], [t8].[Id0], [t8].[Id00], [t12].[Id], [t12].[Id0], [t17].[Id], [t17].[Id0], [t17].[Id00], [t19].[Id], [t19].[Id0], [o22].[ClientId], [o22].[Id]");
+ SELECT [o7].[Id]
+ FROM [OwnedPerson] AS [o7]
+ WHERE [o7].[Discriminator] = N'LeafA'
+ ) AS [t4] ON [o6].[Id] = [t4].[Id]
+ WHERE [o6].[LeafAAddress_LeafType] IS NOT NULL
+) AS [t5] ON [o].[Id] = [t5].[Id]
+LEFT JOIN [Order] AS [o8] ON [o].[Id] = [o8].[ClientId]
+ORDER BY [o].[Id], [t].[Id], [t].[Id0], [t1].[Id], [t1].[Id0], [t3].[Id], [t3].[Id0], [t5].[Id], [t5].[Id0], [o8].[ClientId], [o8].[Id]");
}
private void AssertSql(params string[] expected)
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPTInheritanceQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPTInheritanceQuerySqlServerTest.cs
index 367072ad212..86f3bc0a6b1 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/TPTInheritanceQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPTInheritanceQuerySqlServerTest.cs
@@ -2,8 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading.Tasks;
-using Microsoft.EntityFrameworkCore.Infrastructure;
-using Microsoft.EntityFrameworkCore.Storage;
using Xunit.Abstractions;
// ReSharper disable InconsistentNaming
diff --git a/test/EFCore.SqlServer.FunctionalTests/TPTTableSplittingSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/TPTTableSplittingSqlServerTest.cs
index 6ea622aec8e..bfd387eb7a3 100644
--- a/test/EFCore.SqlServer.FunctionalTests/TPTTableSplittingSqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/TPTTableSplittingSqlServerTest.cs
@@ -177,6 +177,13 @@ public override void Can_change_dependent_instance_non_derived()
base.Can_change_dependent_instance_non_derived();
AssertSql(
+ @"@p0='Trek Pro Fit Madone 6 Series' (Nullable = false) (Size = 450)
+@p1='Repair' (Size = 4000)
+
+SET NOCOUNT ON;
+INSERT INTO [LicensedOperators] ([VehicleName], [LicenseType])
+VALUES (@p0, @p1);",
+ //
@"@p1='Trek Pro Fit Madone 6 Series' (Nullable = false) (Size = 450)
@p0='repairman' (Size = 4000)
@@ -184,13 +191,6 @@ public override void Can_change_dependent_instance_non_derived()
UPDATE [Vehicles] SET [Operator_Name] = @p0
WHERE [Name] = @p1;
SELECT @@ROWCOUNT;",
- //
- @"@p2='Trek Pro Fit Madone 6 Series' (Nullable = false) (Size = 450)
-@p3='Repair' (Size = 4000)
-
-SET NOCOUNT ON;
-INSERT INTO [LicensedOperators] ([VehicleName], [LicenseType])
-VALUES (@p2, @p3);",
//
@"SELECT TOP(2) [v].[Name], [v].[SeatingCapacity], CASE
WHEN [p].[Name] IS NOT NULL THEN N'PoweredVehicle'
diff --git a/test/EFCore.SqlServer.Tests/Migrations/SqlServerModelDifferTest.cs b/test/EFCore.SqlServer.Tests/Migrations/SqlServerModelDifferTest.cs
index ca98643251b..179a7f90c88 100644
--- a/test/EFCore.SqlServer.Tests/Migrations/SqlServerModelDifferTest.cs
+++ b/test/EFCore.SqlServer.Tests/Migrations/SqlServerModelDifferTest.cs
@@ -1015,6 +1015,12 @@ public void Noop_TPT_with_FKs_and_seed_data()
source.Entity("Cat", b =>
{
+ b.HasOne("Animal", null)
+ .WithOne()
+ .HasForeignKey("Cat", "Id")
+ .OnDelete(DeleteBehavior.ClientCascade)
+ .IsRequired();
+
b.HasOne("Animal", null)
.WithMany()
.HasForeignKey("PreyId");
@@ -1022,10 +1028,25 @@ public void Noop_TPT_with_FKs_and_seed_data()
source.Entity("Dog", b =>
{
+ b.HasOne("Animal", null)
+ .WithOne()
+ .HasForeignKey("Dog", "Id")
+ .OnDelete(DeleteBehavior.ClientCascade)
+ .IsRequired();
+
b.HasOne("Animal", null)
.WithMany()
.HasForeignKey("PreyId");
});
+
+ source.Entity("Mouse", b =>
+ {
+ b.HasOne("Animal", null)
+ .WithOne()
+ .HasForeignKey("Mouse", "Id")
+ .OnDelete(DeleteBehavior.ClientCascade)
+ .IsRequired();
+ });
},
modelBuilder =>
{
diff --git a/test/EFCore.Tests/Infrastructure/ModelValidatorTest.cs b/test/EFCore.Tests/Infrastructure/ModelValidatorTest.cs
index 9e7cd2f83fc..3ac4b7a3d98 100644
--- a/test/EFCore.Tests/Infrastructure/ModelValidatorTest.cs
+++ b/test/EFCore.Tests/Infrastructure/ModelValidatorTest.cs
@@ -883,15 +883,16 @@ public virtual void Detects_owned_entity_type_without_ownership()
public virtual void Detects_ForeignKey_on_inherited_generated_key_property()
{
var modelBuilder = CreateConventionalModelBuilder();
- modelBuilder.Entity().Property(e => e.Id).ValueGeneratedOnAdd();
- modelBuilder.Entity>().HasOne().WithOne().HasForeignKey>(e => e.Id);
+ modelBuilder.Entity().Property("SomeId").ValueGeneratedOnAdd();
+ modelBuilder.Entity().HasAlternateKey("SomeId");
+ modelBuilder.Entity>().HasOne().WithOne().HasForeignKey>("SomeId");
modelBuilder.Entity>();
VerifyError(
CoreStrings.ForeignKeyPropertyInKey(
- nameof(Abstract.Id),
+ "SomeId",
"Generic",
- "{'" + nameof(Abstract.Id) + "'}",
+ "{'SomeId'}",
nameof(Abstract)), modelBuilder.Model);
}
diff --git a/test/EFCore.Tests/Metadata/Conventions/ValueGeneratorConventionTest.cs b/test/EFCore.Tests/Metadata/Conventions/ValueGeneratorConventionTest.cs
index e8293fbbfdc..cfdefec16a8 100644
--- a/test/EFCore.Tests/Metadata/Conventions/ValueGeneratorConventionTest.cs
+++ b/test/EFCore.Tests/Metadata/Conventions/ValueGeneratorConventionTest.cs
@@ -447,29 +447,23 @@ public void Identity_is_added_when_foreign_key_is_removed_and_key_is_primary_key
#endregion
private static void RunConvention(InternalEntityTypeBuilder entityBuilder)
- {
- new ValueGenerationConvention(CreateDependencies())
+ => new ValueGenerationConvention(CreateDependencies())
.ProcessEntityTypePrimaryKeyChanged(
entityBuilder, entityBuilder.Metadata.FindPrimaryKey(), null,
new ConventionContext(entityBuilder.Metadata.Model.ConventionDispatcher));
- }
private static void RunConvention(InternalForeignKeyBuilder foreignKeyBuilder)
- {
- new ValueGenerationConvention(CreateDependencies())
+ => new ValueGenerationConvention(CreateDependencies())
.ProcessForeignKeyAdded(
foreignKeyBuilder,
new ConventionContext(
foreignKeyBuilder.Metadata.DeclaringEntityType.Model.ConventionDispatcher));
- }
private static void RunConvention(InternalEntityTypeBuilder entityBuilder, ForeignKey foreignKey)
- {
- new ValueGenerationConvention(CreateDependencies())
+ => new ValueGenerationConvention(CreateDependencies())
.ProcessForeignKeyRemoved(
entityBuilder, foreignKey,
new ConventionContext(entityBuilder.Metadata.Model.ConventionDispatcher));
- }
private static ProviderConventionSetBuilderDependencies CreateDependencies()
=> InMemoryTestHelpers.Instance.CreateContextServices().GetRequiredService();
diff --git a/test/EFCore.Tests/Metadata/Internal/ForeignKeyTest.cs b/test/EFCore.Tests/Metadata/Internal/ForeignKeyTest.cs
index 6375d48c916..90d3456a659 100644
--- a/test/EFCore.Tests/Metadata/Internal/ForeignKeyTest.cs
+++ b/test/EFCore.Tests/Metadata/Internal/ForeignKeyTest.cs
@@ -282,8 +282,7 @@ private IMutableForeignKey CreateOneToManySameBaseFK()
var dependentEntityType = model.AddEntityType(typeof(OneToManyDependent));
dependentEntityType.BaseType = baseEntityType;
- var fkProp = dependentEntityType.AddProperty("Fk", typeof(int));
- var fk = dependentEntityType.AddForeignKey(new[] { fkProp }, pk, principalEntityType);
+ var fk = dependentEntityType.AddForeignKey(new[] { property1 }, pk, principalEntityType);
fk.SetPrincipalToDependent(NavigationBase.OneToManyDependentsProperty);
fk.SetDependentToPrincipal(NavigationBase.OneToManyPrincipalProperty);
return fk;
@@ -299,8 +298,7 @@ private IMutableForeignKey CreateOneToManySameHierarchyFK()
var dependentEntityType = model.AddEntityType(typeof(OneToManyDependent));
dependentEntityType.BaseType = baseEntityType;
- var fkProp = dependentEntityType.AddProperty("Fk", typeof(int));
- var fk = dependentEntityType.AddForeignKey(new[] { fkProp }, pk, baseEntityType);
+ var fk = dependentEntityType.AddForeignKey(new[] { property1 }, pk, baseEntityType);
fk.SetPrincipalToDependent(NavigationBase.OneToManyDependentsProperty);
return fk;
}
@@ -417,14 +415,13 @@ private IMutableForeignKey CreateSelfRefFK(bool useAltKey = false)
{
var entityType = CreateModel().AddEntityType(typeof(SelfRef));
var pk = entityType.SetPrimaryKey(entityType.AddProperty(SelfRef.IdProperty));
- var fkProp = entityType.AddProperty(SelfRef.SelfRefIdProperty);
var property = entityType.AddProperty("AltId", typeof(int));
var principalKey = useAltKey
? entityType.AddKey(property)
: pk;
- var fk = entityType.AddForeignKey(new[] { fkProp }, principalKey, entityType);
+ var fk = entityType.AddForeignKey(new[] { pk.Properties.Single() }, principalKey, entityType);
fk.IsUnique = true;
fk.SetDependentToPrincipal(SelfRef.SelfRefPrincipalProperty);
fk.SetPrincipalToDependent(SelfRef.SelfRefDependentProperty);
@@ -485,35 +482,35 @@ public void IsSelfReferencing_returns_false_for_non_hierarchical_foreign_keys()
}
[ConditionalFact]
- public void IsSelfPrimaryKeyReferencing_returns_true_for_self_ref_foreign_keys()
+ public void IsBaseLinking_returns_true_for_self_ref_foreign_keys()
{
var fk = CreateSelfRefFK();
- Assert.True(fk.IsSelfPrimaryKeyReferencing());
+ Assert.True(fk.IsBaseLinking());
}
[ConditionalFact]
- public void IsSelfPrimaryKeyReferencing_returns_false_for_non_pk_self_ref_foreign_keys()
+ public void IsBaseLinking_returns_false_for_non_pk_self_ref_foreign_keys()
{
var fk = CreateSelfRefFK(useAltKey: true);
- Assert.False(fk.IsSelfPrimaryKeyReferencing());
+ Assert.False(fk.IsBaseLinking());
}
[ConditionalFact]
- public void IsSelfPrimaryKeyReferencing_returns_true_for_same_hierarchy_foreign_keys()
+ public void IsBaseLinking_returns_true_for_same_hierarchy_foreign_keys()
{
var fk = CreateOneToManySameHierarchyFK();
- Assert.True(fk.IsSelfPrimaryKeyReferencing());
+ Assert.True(fk.IsBaseLinking());
}
[ConditionalFact]
- public void IsSelfPrimaryKeyReferencing_returns_true_for_same_base_foreign_keys()
+ public void IsBaseLinking_returns_true_for_same_base_foreign_keys()
{
var fk = CreateOneToManySameBaseFK();
- Assert.True(fk.IsSelfPrimaryKeyReferencing());
+ Assert.True(fk.IsBaseLinking());
}
[ConditionalFact]
@@ -521,7 +518,7 @@ public void IsSelfPrimaryKeyReferencing_returns_false_for_non_hierarchical_forei
{
var fk = CreateOneToManyFK();
- Assert.False(fk.IsSelfPrimaryKeyReferencing());
+ Assert.False(fk.IsBaseLinking());
}
[ConditionalFact]