diff --git a/src/EFCore.Relational/Metadata/Conventions/TableSharingConcurrencyTokenConvention.cs b/src/EFCore.Relational/Metadata/Conventions/TableSharingConcurrencyTokenConvention.cs index 3af0ff9745c..0d4782274ad 100644 --- a/src/EFCore.Relational/Metadata/Conventions/TableSharingConcurrencyTokenConvention.cs +++ b/src/EFCore.Relational/Metadata/Conventions/TableSharingConcurrencyTokenConvention.cs @@ -45,28 +45,27 @@ public virtual void ProcessModelFinalizing( IConventionModelBuilder modelBuilder, IConventionContext context) { - var tableToEntityTypes = new Dictionary<(string Name, string? Schema), List>(); + var tableToEntityTypes = new Dictionary>(); foreach (var entityType in modelBuilder.Metadata.GetEntityTypes()) { - var tableName = entityType.GetTableName(); - if (tableName == null) + var table = StoreObjectIdentifier.Create(entityType, StoreObjectType.Table); + if (table == null) { continue; } - var table = (tableName, entityType.GetSchema()); - if (!tableToEntityTypes.TryGetValue(table, out var mappedTypes)) + if (!tableToEntityTypes.TryGetValue(table.Value, out var mappedTypes)) { mappedTypes = new List(); - tableToEntityTypes[table] = mappedTypes; + tableToEntityTypes[table.Value] = mappedTypes; } mappedTypes.Add(entityType); } - foreach (var ((name, schema), mappedTypes) in tableToEntityTypes) + foreach (var (table, mappedTypes) in tableToEntityTypes) { - var concurrencyColumns = GetConcurrencyTokensMap(StoreObjectIdentifier.Table(name, schema), mappedTypes); + var concurrencyColumns = GetConcurrencyTokensMap(table, mappedTypes); if (concurrencyColumns == null) { continue; @@ -81,7 +80,7 @@ public virtual void ProcessModelFinalizing( var foundMappedProperty = !IsConcurrencyTokenMissing(readOnlyProperties, entityType, mappedTypes) || entityType.GetProperties() - .Any(p => p.GetColumnName(StoreObjectIdentifier.Table(name, schema)) == concurrencyColumnName); + .Any(p => p.GetColumnName(table) == concurrencyColumnName); if (!foundMappedProperty) { @@ -158,8 +157,8 @@ public virtual void ProcessModelFinalizing( var nonHierarchyTypesCount = 0; foreach (var entityType in mappedTypes) { - if (entityType.BaseType == null - || !mappedTypes.Contains(entityType.BaseType)) + if ((entityType.BaseType == null && !mappedTypes.Any(t => t.BaseType == entityType)) + || (entityType.BaseType != null && !mappedTypes.Contains(entityType.BaseType))) { nonHierarchyTypesCount++; } @@ -167,14 +166,14 @@ public virtual void ProcessModelFinalizing( concurrencyColumns = FindConcurrencyColumns(entityType, storeObject, concurrencyColumns); } - return nonHierarchyTypesCount < 2 ? null : concurrencyColumns; + return nonHierarchyTypesCount < 1 ? null : concurrencyColumns; static Dictionary>? FindConcurrencyColumns( IReadOnlyTypeBase structuralType, StoreObjectIdentifier storeObject, Dictionary>? concurrencyColumns) { - foreach (var property in structuralType.GetDeclaredProperties()) + foreach (var property in structuralType.GetProperties()) { if (!property.IsConcurrencyToken || (property.ValueGenerated & ValueGenerated.OnUpdate) == 0) @@ -198,7 +197,7 @@ public virtual void ProcessModelFinalizing( properties.Add(property); } - foreach (var complexProperty in structuralType.GetDeclaredComplexProperties()) + foreach (var complexProperty in structuralType.GetComplexProperties()) { concurrencyColumns = FindConcurrencyColumns(complexProperty.ComplexType, storeObject, concurrencyColumns); } diff --git a/src/EFCore.Relational/Metadata/ITable.cs b/src/EFCore.Relational/Metadata/ITable.cs index 185f209ba18..bfcaa5b0c51 100644 --- a/src/EFCore.Relational/Metadata/ITable.cs +++ b/src/EFCore.Relational/Metadata/ITable.cs @@ -95,6 +95,7 @@ string ITableBase.ToDebugString(MetadataDebugStringOptions options, int indent) { var builder = new StringBuilder(); var indentString = new string(' ', indent); + var designTime = EntityTypeMappings.FirstOrDefault()?.TypeBase is not RuntimeEntityType; try { @@ -111,8 +112,8 @@ string ITableBase.ToDebugString(MetadataDebugStringOptions options, int indent) builder.Append(Name); - if (EntityTypeMappings.Any() - && EntityTypeMappings.First().TypeBase is not RuntimeEntityType + if (designTime + && EntityTypeMappings.Any() && IsExcludedFromMigrations) { builder.Append(" ExcludedFromMigrations"); @@ -132,7 +133,9 @@ string ITableBase.ToDebugString(MetadataDebugStringOptions options, int indent) builder.Append(PrimaryKey.ToDebugString(options, indent + 2)); } - if ((options & MetadataDebugStringOptions.SingleLine) == 0 && Comment != null) + if ((options & MetadataDebugStringOptions.SingleLine) == 0 + && designTime + && Comment != null) { builder .AppendLine() @@ -194,13 +197,16 @@ string ITableBase.ToDebugString(MetadataDebugStringOptions options, int indent) } } - var checkConstraints = CheckConstraints.ToList(); - if (checkConstraints.Count != 0) + if (designTime) { - builder.AppendLine().Append(indentString).Append(" Check constraints: "); - foreach (var checkConstraint in checkConstraints) + var checkConstraints = CheckConstraints.ToList(); + if (checkConstraints.Count != 0) { - builder.AppendLine().Append(checkConstraint.ToDebugString(options, indent + 4)); + builder.AppendLine().Append(indentString).Append(" Check constraints: "); + foreach (var checkConstraint in checkConstraints) + { + builder.AppendLine().Append(checkConstraint.ToDebugString(options, indent + 4)); + } } } diff --git a/test/EFCore.SqlServer.FunctionalTests/OptimisticConcurrencySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/OptimisticConcurrencySqlServerTest.cs index 78b0c53df2b..544b1ca800c 100644 --- a/test/EFCore.SqlServer.FunctionalTests/OptimisticConcurrencySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/OptimisticConcurrencySqlServerTest.cs @@ -149,7 +149,7 @@ await c.Database.CreateExecutionStrategy().ExecuteAsync( var fanVersion1 = fanEntry.Property(propertyName).CurrentValue; var swagVersion1 = default(TVersion); - if (mapping == Mapping.Tph) // Issue #29750 + if (mapping != Mapping.Tpt) // Issue #22060 { swagVersion1 = swagEntry.Property(synthesizedPropertyName).CurrentValue; @@ -190,7 +190,7 @@ await c.Database.CreateExecutionStrategy().ExecuteAsync( Assert.NotEqual(fanVersion1, fanVersion2); var swagVersion2 = default(TVersion); - if (mapping == Mapping.Tph) // Issue #29750 + if (mapping != Mapping.Tpt) // Issue #22060 { swagVersion2 = swagEntry.Property(synthesizedPropertyName).CurrentValue; Assert.Equal(fanVersion2, swagVersion2); @@ -229,7 +229,7 @@ await c.Database.CreateExecutionStrategy().ExecuteAsync( var fanVersion3 = fanEntry.Property(propertyName).CurrentValue; Assert.NotEqual(fanVersion2, fanVersion3); - if (mapping == Mapping.Tph) // Issue #29750 + if (mapping != Mapping.Tpt) // Issue #22060 { var swagVersion3 = swagEntry.Property(synthesizedPropertyName).CurrentValue; Assert.Equal(fanVersion3, swagVersion3); @@ -261,7 +261,7 @@ await c.Database.CreateExecutionStrategy().ExecuteAsync( var circuitVersion1 = circuitEntry.Property(propertyName).CurrentValue; var cityVersion1 = default(TVersion); - if (mapping == Mapping.Tph) // Issue #29750 + if (mapping != Mapping.Tpt) // Issue #22060 { cityVersion1 = cityEntry.Property(synthesizedPropertyName).CurrentValue; @@ -302,7 +302,7 @@ await c.Database.CreateExecutionStrategy().ExecuteAsync( Assert.NotEqual(circuitVersion1, circuitVersion2); var cityVersion2 = default(TVersion); - if (mapping == Mapping.Tph) // Issue #29750 + if (mapping != Mapping.Tpt) // Issue #22060 { cityVersion2 = cityEntry.Property(synthesizedPropertyName).CurrentValue; Assert.Equal(circuitVersion2, cityVersion2); @@ -341,7 +341,7 @@ await c.Database.CreateExecutionStrategy().ExecuteAsync( var circuitVersion3 = circuitEntry.Property(propertyName).CurrentValue; Assert.NotEqual(circuitVersion2, circuitVersion3); - if (mapping == Mapping.Tph) // Issue #29750 + if (mapping != Mapping.Tpt) // Issue #22060 { var cityVersion3 = cityEntry.Property(synthesizedPropertyName).CurrentValue; Assert.Equal(circuitVersion3, cityVersion3);