Skip to content

Commit 4dbb574

Browse files
authored
Merge pull request #39348 from dotnet/merge/release/11.0-to-main
[automated] Merge branch 'release/11.0' => 'main'
2 parents 28f7c87 + c876951 commit 4dbb574

17 files changed

Lines changed: 894 additions & 789 deletions

File tree

‎NuGet.config‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<clear />
55
<!--Begin: Package sources managed by Dependency Flow automation. Do not edit the sources below.-->
66
<!-- Begin: Package sources from dotnet-dotnet -->
7+
<add key="darc-pub-dotnet-dotnet-a586537-1" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/darc-pub-dotnet-dotnet-a586537b-1/nuget/v3/index.json" />
78
<!-- End: Package sources from dotnet-dotnet -->
89
<!-- Begin: Package sources from dotnet-runtime -->
910
<!-- End: Package sources from dotnet-runtime -->

‎src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,8 @@ public static string GetDefaultColumnName(this IReadOnlyProperty property)
231231
else if (StoreObjectIdentifier.Create(property.DeclaringType, currentStoreObject.StoreObjectType) == currentStoreObject
232232
|| property.DeclaringType.GetMappingFragments(storeObject.StoreObjectType)
233233
.Any(f => f.StoreObject == currentStoreObject)
234-
|| (property.IsPrimaryKey()
234+
|| ((property.IsPrimaryKey()
235+
|| property.DeclaringType.ContainingEntityType.GetMappingStrategy() == RelationalAnnotationNames.TpcMappingStrategy)
235236
&& property.DeclaringType.ContainingEntityType.GetDerivedTypes()
236237
.Any(e => StoreObjectIdentifier.Create(e, currentStoreObject.StoreObjectType) == currentStoreObject)))
237238
{

‎src/EFCore.Relational/Metadata/Internal/RelationalModel.cs‎

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -299,19 +299,7 @@ private static void AddDefaultMappings(
299299
? !isTpc && mappedType == entityType
300300
: null);
301301

302-
var containerColumnName = mappedType.GetContainerColumnName();
303-
var containerColumnType = mappedType.GetContainerColumnType();
304-
if (!string.IsNullOrEmpty(containerColumnName))
305-
{
306-
CreateContainerColumn(
307-
defaultTable, containerColumnName, containerColumnType, mappedType, relationalTypeMappingSource,
308-
static (colName, colType, table, mapping) => new JsonColumnBase(
309-
colName, colType ?? mapping.StoreType, table, mapping), tableMapping);
310-
}
311-
else
312-
{
313-
CreateDefaultColumnMapping(entityType, mappedType, defaultTable, tableMapping, isTph, isTpc, relationalTypeMappingSource);
314-
}
302+
CreateDefaultColumnMapping(entityType, mappedType, defaultTable, tableMapping, isTph, isTpc, relationalTypeMappingSource);
315303

316304
if (((ITableMappingBase)tableMapping).ColumnMappings.Any()
317305
|| tableMappings.Count == 0)
@@ -340,32 +328,44 @@ private static void CreateDefaultColumnMapping(
340328
bool isTpc,
341329
IRelationalTypeMappingSource relationalTypeMappingSource)
342330
{
343-
foreach (var property in typeBase.GetProperties())
331+
var containerColumnName = mappedType.GetContainerColumnName();
332+
var containerColumnType = mappedType.GetContainerColumnType();
333+
if (!string.IsNullOrEmpty(containerColumnName))
344334
{
345-
var columnName = property.IsPrimaryKey() || isTpc || isTph || property.DeclaringType == mappedType
346-
? GetColumnName(property)
347-
: null;
348-
349-
if (columnName == null)
335+
CreateContainerColumn(
336+
defaultTable, containerColumnName, containerColumnType, mappedType, relationalTypeMappingSource,
337+
static (colName, colType, table, mapping) => new JsonColumnBase(
338+
colName, colType ?? mapping.StoreType, table, mapping), tableMapping);
339+
}
340+
else
341+
{
342+
foreach (var property in typeBase.GetProperties())
350343
{
351-
continue;
352-
}
344+
var columnName = property.IsPrimaryKey() || isTpc || isTph || property.DeclaringType == mappedType
345+
? GetColumnName(property)
346+
: null;
353347

354-
var column = (ColumnBase<ColumnMappingBase>?)defaultTable.FindColumn(columnName);
355-
if (column == null)
356-
{
357-
column = new ColumnBase<ColumnMappingBase>(columnName, property.GetColumnType(), defaultTable)
348+
if (columnName == null)
358349
{
359-
IsNullable = property.IsColumnNullable()
360-
};
361-
defaultTable.Columns.Add(columnName, column);
362-
}
363-
else if (!property.IsColumnNullable())
364-
{
365-
column.IsNullable = false;
366-
}
350+
continue;
351+
}
367352

368-
CreateColumnMapping(column, property, tableMapping);
353+
var column = (ColumnBase<ColumnMappingBase>?)defaultTable.FindColumn(columnName);
354+
if (column == null)
355+
{
356+
column = new ColumnBase<ColumnMappingBase>(columnName, property.GetColumnType(), defaultTable)
357+
{
358+
IsNullable = property.IsColumnNullable()
359+
};
360+
defaultTable.Columns.Add(columnName, column);
361+
}
362+
else if (!property.IsColumnNullable())
363+
{
364+
column.IsNullable = false;
365+
}
366+
367+
CreateColumnMapping(column, property, tableMapping);
368+
}
369369
}
370370

371371
foreach (var complexProperty in typeBase.GetDeclaredComplexProperties())

‎src/EFCore/Storage/Json/JsonCollectionOfNullableStructsReaderWriter.cs‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,10 @@ public JsonCollectionOfNullableStructsReaderWriter(JsonValueReaderWriter<TElemen
7373
case JsonTokenType.Number:
7474
case JsonTokenType.True:
7575
case JsonTokenType.False:
76-
collection.Add(_elementReaderWriter.FromJsonTyped(ref manager));
76+
collection.Add(
77+
_elementReaderWriter.GetType() == typeof(JsonCastValueReaderWriter<TElement>)
78+
? (TElement?)((ICompositeJsonValueReaderWriter)_elementReaderWriter).InnerReaderWriter.FromJson(ref manager)
79+
: _elementReaderWriter.FromJsonTyped(ref manager));
7780
break;
7881
case JsonTokenType.Null:
7982
collection.Add(null);

‎test/EFCore.Cosmos.FunctionalTests/JsonTypesCosmosTest.cs‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,16 @@ public override Task Can_read_write_collection_of_nullable_int_with_converter_JS
138138
// Cosmos provider cannot map collections of elements with converters. See Issue #34026.
139139
=> Assert.ThrowsAsync<InvalidOperationException>(base.Can_read_write_collection_of_nullable_int_with_converter_JSON_values);
140140

141+
public override void Can_read_write_collection_of_nullable_int_with_null_returning_converter(bool existingCollection)
142+
// Cosmos provider cannot map collections of elements with converters. See Issue #34026.
143+
=> Assert.Throws<InvalidOperationException>(
144+
() => base.Can_read_write_collection_of_nullable_int_with_null_returning_converter(existingCollection));
145+
146+
public override void Can_read_write_collection_of_nullable_struct_with_null_returning_converter(bool existingCollection)
147+
// Cosmos provider cannot map collections of elements with converters. See Issue #34026.
148+
=> Assert.Throws<InvalidOperationException>(
149+
() => base.Can_read_write_collection_of_nullable_struct_with_null_returning_converter(existingCollection));
150+
141151
public override Task Can_read_write_collection_of_nullable_IP_address_JSON_values()
142152
// Cosmos provider cannot map collections of elements with converters. See Issue #34026.
143153
=> Assert.ThrowsAsync<InvalidOperationException>(base.Can_read_write_collection_of_nullable_IP_address_JSON_values);

‎test/EFCore.Relational.Specification.Tests/Query/Associations/ComplexJson/ComplexJsonMiscellaneousRelationalTestBase.cs‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@ public ComplexJsonMiscellaneousRelationalTestBase(TFixture fixture, ITestOutputH
1919
public virtual Task FromSql_on_root()
2020
=> RelationalAssociationsTests.FromSql_on_root(this, Fixture);
2121

22+
[Theory, MemberData(nameof(IsAsyncData))]
23+
public virtual Task FromSql_on_root_composed(bool async)
24+
=> AssertQuery(
25+
async,
26+
ss => ((DbSet<RootEntity>)ss.Set<RootEntity>())
27+
.FromSqlRaw(((RelationalTestStore)Fixture.TestStore).NormalizeDelimitersInRawString("SELECT * FROM [RootEntity]"))
28+
.Where(e => e.RequiredAssociate.Int == 8),
29+
ss => ss.Set<RootEntity>().Where(e => e.RequiredAssociate.Int == 8));
30+
2231
protected void AssertSql(params string[] expected)
2332
=> Fixture.TestSqlLoggerFactory.AssertBaseline(expected);
2433
}

‎test/EFCore.Relational.Specification.Tests/Scaffolding/CompiledModelRelationalTestBase.cs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -641,7 +641,8 @@ protected override void AssertComplexTypes(IModel model)
641641
Assert.NotEmpty(elementObject.Properties);
642642

643643
// Verify GetJsonElementMappings works for the complex property
644-
var mappings = manyOwnedComplexProperty.GetJsonElementMappings().ToList();
644+
var mappings = manyOwnedComplexProperty.GetJsonElementMappings()
645+
.Where(m => m.TableMapping.Table == principalDerivedTable).ToList();
645646
Assert.NotEmpty(mappings);
646647
Assert.All(
647648
mappings, m =>

‎test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs‎

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -557,11 +557,14 @@ private static void AssertViews(IRelationalModel model, Mapping mapping)
557557

558558
Assert.Null(customerView.EntityTypeMappings.Single().IsSharedTablePrincipal);
559559
Assert.Null(customerView.EntityTypeMappings.Single().IsSplitEntityTypePrincipal);
560-
Assert.Equal(5, customerView.Columns.Count());
560+
Assert.Equal(6, customerView.Columns.Count());
561+
Assert.Same(
562+
abstractBaseType.FindComplexProperty(nameof(AbstractBase.Tag))!.ComplexType.FindProperty(nameof(Tag.Name)),
563+
Assert.Single(customerView.FindColumn("Tag_Name")!.PropertyMappings).Property);
561564

562565
Assert.Single(specialCustomerView.EntityTypeMappings);
563566

564-
Assert.Equal(9, specialCustomerView.Columns.Count());
567+
Assert.Equal(10, specialCustomerView.Columns.Count());
565568

566569
Assert.False(specialtyColumn.IsNullable);
567570

@@ -571,7 +574,7 @@ private static void AssertViews(IRelationalModel model, Mapping mapping)
571574
Assert.False(extraSpecialCustomerView.EntityTypeMappings.Last().IsSharedTablePrincipal);
572575
Assert.Null(extraSpecialCustomerView.EntityTypeMappings.Last().IsSplitEntityTypePrincipal);
573576

574-
Assert.Equal(11, extraSpecialCustomerView.Columns.Count());
577+
Assert.Equal(12, extraSpecialCustomerView.Columns.Count());
575578
}
576579
}
577580
}
@@ -799,6 +802,12 @@ private static void AssertTables(IRelationalModel model, Mapping mapping)
799802

800803
var complexType = abstractBaseType.GetComplexProperties().Single().ComplexType;
801804

805+
foreach (var columnMapping in complexType.GetTableMappings().SelectMany(m => m.ColumnMappings))
806+
{
807+
Assert.Equal("Tag_Name", columnMapping.Column.Name);
808+
Assert.Same(complexType.FindProperty(nameof(Tag.Name)), columnMapping.Property);
809+
}
810+
802811
if (mapping == Mapping.TPT)
803812
{
804813
var baseTable = abstractBaseType.GetTableMappings().Single().Table;
@@ -3658,8 +3667,8 @@ public void Json_element_tree_is_built_for_owned_entity_json_columns()
36583667
Assert.All(datePropertyMappings, m => Assert.Equal("Date", m.Element.PropertyName));
36593668
}
36603669

3661-
[Fact]
3662-
public void Json_element_tree_is_merged_for_existing_json_columns()
3670+
[Theory, InlineData(false), InlineData(true)]
3671+
public void Json_element_tree_is_merged_for_existing_json_columns(bool defaultMapping)
36633672
{
36643673
var modelBuilder = CreateConventionModelBuilder();
36653674

@@ -3669,28 +3678,35 @@ public void Json_element_tree_is_merged_for_existing_json_columns()
36693678
b => b.ToJson("complex_data"));
36703679

36713680
var model = Finalize(modelBuilder);
3672-
var table = model.Tables.Single();
3681+
var entityType = model.Model.FindEntityType(typeof(EntityWithNestedComplexProperty))!;
3682+
var table = defaultMapping
3683+
? entityType.GetDefaultMappings().Single().Table
3684+
: model.Tables.Single();
36733685
var jsonColumn = table.FindColumn("complex_data")!;
36743686

36753687
var jsonObject = Assert.IsAssignableFrom<IRelationalJsonObject>(jsonColumn.JsonElement);
36763688
var nestedObject = Assert.IsAssignableFrom<IRelationalJsonObject>(jsonObject.FindProperty("Nested"));
36773689
Assert.NotNull(nestedObject.FindProperty("Number"));
36783690

3679-
var entityType = model.Model.FindEntityType(typeof(EntityWithNestedComplexProperty))!;
36803691
var complexProperty = entityType.FindComplexProperty(nameof(EntityWithNestedComplexProperty.ComplexProperty))!;
36813692
var nestedComplexProperty = complexProperty.ComplexType.FindComplexProperty(nameof(OuterComplexData.Nested))!;
36823693

36833694
Assert.Same(jsonColumn, table.FindColumn(complexProperty));
36843695
Assert.Same(jsonColumn, table.FindColumn(nestedComplexProperty));
3696+
Assert.Same(
3697+
table,
3698+
defaultMapping
3699+
? nestedComplexProperty.ComplexType.GetDefaultMappings().Single().Table
3700+
: nestedComplexProperty.ComplexType.GetTableMappings().Single().Table);
36853701

36863702
var numberProperty = nestedComplexProperty.ComplexType.FindProperty(nameof(NestedComplexData.Number))!;
36873703
var numberMappings = numberProperty.GetJsonElementMappings().ToList();
36883704
Assert.NotEmpty(numberMappings);
36893705
Assert.All(numberMappings, m => Assert.Equal("Number", m.Element.PropertyName));
36903706
}
36913707

3692-
[Fact]
3693-
public void Json_element_tree_is_built_for_complex_property_json_columns()
3708+
[Theory, InlineData(false), InlineData(true)]
3709+
public void Json_element_tree_is_built_for_complex_property_json_columns(bool defaultMapping)
36943710
{
36953711
var modelBuilder = CreateConventionModelBuilder();
36963712

@@ -3699,7 +3715,10 @@ public void Json_element_tree_is_built_for_complex_property_json_columns()
36993715
e => e.ComplexProperty, b => b.ToJson("complex_data"));
37003716

37013717
var model = Finalize(modelBuilder);
3702-
var table = model.Tables.Single();
3718+
var entityType = model.Model.FindEntityType(typeof(EntityWithComplexProperty))!;
3719+
var table = defaultMapping
3720+
? entityType.GetDefaultMappings().Single().Table
3721+
: model.Tables.Single();
37033722

37043723
// Validate JsonElement on column
37053724
var jsonColumn = table.FindColumn("complex_data")!;
@@ -3730,21 +3749,20 @@ public void Json_element_tree_is_built_for_complex_property_json_columns()
37303749
Assert.False(numberProp.IsNullable);
37313750

37323751
// Validate FindColumn(IPropertyBase) with complex property
3733-
var entityType = model.Model.FindEntityType(typeof(EntityWithComplexProperty))!;
37343752
var complexProperty = entityType.FindComplexProperty(nameof(EntityWithComplexProperty.ComplexProperty))!;
37353753
var column = table.FindColumn(complexProperty);
37363754
Assert.NotNull(column);
37373755
Assert.Equal("complex_data", column.Name);
37383756
Assert.Same(root, column.JsonElement);
37393757

37403758
// Validate GetJsonElementMappings for complex property
3741-
var complexMappings = complexProperty.GetJsonElementMappings().ToList();
3759+
var complexMappings = complexProperty.GetJsonElementMappings().Where(m => m.TableMapping.Table == table).ToList();
37423760
Assert.Single(complexMappings);
37433761
Assert.Same(root, complexMappings[0].Element);
37443762

37453763
// Validate scalar properties have mappings
37463764
var valueProperty = complexProperty.ComplexType.FindProperty("Value")!;
3747-
var valueMappings = valueProperty.GetJsonElementMappings().ToList();
3765+
var valueMappings = valueProperty.GetJsonElementMappings().Where(m => m.TableMapping.Table == table).ToList();
37483766
Assert.Single(valueMappings);
37493767
Assert.Equal("Value", valueMappings[0].Element.PropertyName);
37503768
Assert.Same((RelationalTypeMapping)valueProperty.GetTypeMapping(), valueMappings[0].Element.StoreTypeMapping);

‎test/EFCore.Relational.Tests/Migrations/Internal/MigrationsModelDifferTest.cs‎

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8862,6 +8862,50 @@ public void Change_TPT_to_TPC_with_FKs_and_seed_data()
88628862
Assert.Equal(ReferentialAction.Cascade, operation.OnDelete);
88638863
}));
88648864

8865+
[Fact]
8866+
public void Add_second_inherited_complex_property_in_TPC_does_not_reassign_existing_columns()
8867+
=> Execute(
8868+
common =>
8869+
{
8870+
common.Entity("Vessel", b =>
8871+
{
8872+
b.UseTpcMappingStrategy();
8873+
b.Property<int>("Id");
8874+
b.ComplexProperty<Address>("Shipping", c =>
8875+
{
8876+
c.IsRequired();
8877+
c.Ignore(a => a.AddressLine2);
8878+
});
8879+
});
8880+
common.Entity("Ferry").HasBaseType("Vessel");
8881+
},
8882+
_ => { },
8883+
target => target.Entity("Vessel").ComplexProperty<Address>("Billing", c =>
8884+
{
8885+
c.IsRequired();
8886+
c.Ignore(a => a.AddressLine2);
8887+
}),
8888+
upOperations =>
8889+
{
8890+
Assert.Equal(2, upOperations.Count);
8891+
Assert.Equal(["Ferry", "Vessel"], upOperations.Cast<AddColumnOperation>().Select(o => o.Table).Order());
8892+
foreach (var operation in upOperations)
8893+
{
8894+
var addColumn = Assert.IsType<AddColumnOperation>(operation);
8895+
Assert.Equal("Billing_AddressLine1", addColumn.Name);
8896+
}
8897+
},
8898+
downOperations =>
8899+
{
8900+
Assert.Equal(2, downOperations.Count);
8901+
Assert.Equal(["Ferry", "Vessel"], downOperations.Cast<DropColumnOperation>().Select(o => o.Table).Order());
8902+
foreach (var operation in downOperations)
8903+
{
8904+
var dropColumn = Assert.IsType<DropColumnOperation>(operation);
8905+
Assert.Equal("Billing_AddressLine1", dropColumn.Name);
8906+
}
8907+
});
8908+
88658909
[Fact]
88668910
public void Change_TPT_to_TPC_with_excluded_base()
88678911
=> Execute(

0 commit comments

Comments
 (0)