1
1
// Licensed to the .NET Foundation under one or more agreements.
2
2
// The .NET Foundation licenses this file to you under the MIT license.
3
3
4
+ using System . Diagnostics . CodeAnalysis ;
4
5
using System . Globalization ;
5
6
using System . Runtime . CompilerServices ;
6
7
using System . Text ;
@@ -230,21 +231,54 @@ public static string GetDefaultColumnName(this IReadOnlyProperty property)
230
231
StringBuilder ? builder = null ;
231
232
var currentStoreObject = storeObject ;
232
233
if ( property . DeclaringType is IReadOnlyEntityType entityType )
234
+ {
235
+ builder = CreateOwnershipPrefix ( entityType , storeObject , builder ) ;
236
+ }
237
+ else if ( StoreObjectIdentifier . Create ( property . DeclaringType , currentStoreObject . StoreObjectType ) == currentStoreObject
238
+ || property . DeclaringType . GetMappingFragments ( storeObject . StoreObjectType )
239
+ . Any ( f => f . StoreObject == currentStoreObject ) )
240
+ {
241
+ builder = CreateComplexPrefix ( ( IReadOnlyComplexType ) property . DeclaringType , storeObject , builder ) ;
242
+ }
243
+
244
+ var baseName = storeObject . StoreObjectType == StoreObjectType . Table ? property . GetDefaultColumnName ( ) : property . Name ;
245
+ if ( builder == null )
246
+ {
247
+ return baseName ;
248
+ }
249
+
250
+ builder . Append ( baseName ) ;
251
+ baseName = builder . ToString ( ) ;
252
+
253
+ return Uniquifier . Truncate ( baseName , property . DeclaringType . Model . GetMaxIdentifierLength ( ) ) ;
254
+
255
+ [ return : NotNullIfNotNull ( "builder" ) ]
256
+ static StringBuilder ? CreateOwnershipPrefix ( IReadOnlyEntityType entityType , in StoreObjectIdentifier storeObject , StringBuilder ? builder )
233
257
{
234
258
while ( true )
235
259
{
236
260
var ownership = entityType . GetForeignKeys ( ) . SingleOrDefault ( fk => fk . IsOwnership ) ;
237
261
if ( ownership == null )
238
262
{
239
- break ;
263
+ return builder ;
240
264
}
241
265
242
266
var ownerType = ownership . PrincipalEntityType ;
243
- if ( StoreObjectIdentifier . Create ( ownerType , currentStoreObject . StoreObjectType ) != currentStoreObject
244
- && ownerType . GetMappingFragments ( storeObject . StoreObjectType )
245
- . All ( f => f . StoreObject != currentStoreObject ) )
267
+ if ( StoreObjectIdentifier . Create ( ownerType , storeObject . StoreObjectType ) != storeObject )
246
268
{
247
- break ;
269
+ var foundMappedFragment = false ;
270
+ foreach ( var fragment in ownerType . GetMappingFragments ( storeObject . StoreObjectType ) )
271
+ {
272
+ if ( fragment . StoreObject == storeObject )
273
+ {
274
+ foundMappedFragment = true ;
275
+ }
276
+ }
277
+
278
+ if ( ! foundMappedFragment )
279
+ {
280
+ return builder ;
281
+ }
248
282
}
249
283
250
284
builder ??= new StringBuilder ( ) ;
@@ -254,31 +288,27 @@ public static string GetDefaultColumnName(this IReadOnlyProperty property)
254
288
entityType = ownerType ;
255
289
}
256
290
}
257
- else if ( StoreObjectIdentifier . Create ( property . DeclaringType , currentStoreObject . StoreObjectType ) == currentStoreObject
258
- || property . DeclaringType . GetMappingFragments ( storeObject . StoreObjectType )
259
- . Any ( f => f . StoreObject == currentStoreObject ) )
291
+
292
+ static StringBuilder CreateComplexPrefix ( IReadOnlyComplexType complexType , in StoreObjectIdentifier storeObject , StringBuilder ? builder )
260
293
{
261
- var complexType = ( IReadOnlyComplexType ) property . DeclaringType ;
262
294
builder ??= new StringBuilder ( ) ;
263
- while ( complexType != null )
295
+ while ( true )
264
296
{
265
297
builder . Insert ( 0 , "_" ) ;
266
298
builder . Insert ( 0 , complexType . ComplexProperty . Name ) ;
267
299
268
- complexType = complexType . ComplexProperty . DeclaringType as IReadOnlyComplexType ;
300
+ switch ( complexType . ComplexProperty . DeclaringType )
301
+ {
302
+ case IReadOnlyComplexType declaringComplexType :
303
+ complexType = declaringComplexType ;
304
+ break ;
305
+ case IReadOnlyEntityType declaringEntityType :
306
+ return CreateOwnershipPrefix ( declaringEntityType , storeObject , builder ) ;
307
+ default :
308
+ return builder ;
309
+ }
269
310
}
270
311
}
271
-
272
- var baseName = storeObject . StoreObjectType == StoreObjectType . Table ? property . GetDefaultColumnName ( ) : property . Name ;
273
- if ( builder == null )
274
- {
275
- return baseName ;
276
- }
277
-
278
- builder . Append ( baseName ) ;
279
- baseName = builder . ToString ( ) ;
280
-
281
- return Uniquifier . Truncate ( baseName , property . DeclaringType . Model . GetMaxIdentifierLength ( ) ) ;
282
312
}
283
313
284
314
/// <summary>
@@ -1183,15 +1213,21 @@ public static void SetIsFixedLength(this IMutableProperty property, bool? fixedL
1183
1213
/// <remarks>
1184
1214
/// This depends on the property itself and also how it is mapped. For example,
1185
1215
/// derived non-nullable properties in a TPH type hierarchy will be mapped to nullable columns.
1186
- /// As well as properties on optional types sharing the same table.
1187
1216
/// </remarks>
1188
1217
/// <param name="property">The <see cref="IReadOnlyProperty" />.</param>
1189
1218
/// <returns><see langword="true" /> if the mapped column is nullable; <see langword="false" /> otherwise.</returns>
1190
1219
public static bool IsColumnNullable ( this IReadOnlyProperty property )
1191
1220
=> property . IsNullable
1192
1221
|| ( property . DeclaringType . ContainingEntityType is IReadOnlyEntityType entityType
1193
1222
&& entityType . BaseType != null
1194
- && entityType . GetMappingStrategy ( ) == RelationalAnnotationNames . TphMappingStrategy ) ;
1223
+ && entityType . GetMappingStrategy ( ) == RelationalAnnotationNames . TphMappingStrategy )
1224
+ || ( property . DeclaringType is IReadOnlyComplexType complexType
1225
+ && IsNullable ( complexType . ComplexProperty ) ) ;
1226
+
1227
+ private static bool IsNullable ( IReadOnlyComplexProperty complexProperty )
1228
+ => complexProperty . IsNullable
1229
+ || ( complexProperty . DeclaringType is IReadOnlyComplexType complexType
1230
+ && IsNullable ( complexType . ComplexProperty ) ) ;
1195
1231
1196
1232
/// <summary>
1197
1233
/// Checks whether the column mapped to the given property will be nullable
@@ -1222,7 +1258,9 @@ public static bool IsColumnNullable(this IReadOnlyProperty property, in StoreObj
1222
1258
|| ( property . DeclaringType . ContainingEntityType is IReadOnlyEntityType entityType
1223
1259
&& ( ( entityType . BaseType != null
1224
1260
&& entityType . GetMappingStrategy ( ) == RelationalAnnotationNames . TphMappingStrategy )
1225
- || IsOptionalSharingDependent ( entityType , storeObject , 0 ) ) ) ;
1261
+ || IsOptionalSharingDependent ( entityType , storeObject , 0 ) ) )
1262
+ || ( property . DeclaringType is IReadOnlyComplexType complexType
1263
+ && IsNullable ( complexType . ComplexProperty ) ) ;
1226
1264
}
1227
1265
1228
1266
private static bool IsOptionalSharingDependent (
@@ -1476,7 +1514,7 @@ public static RelationalTypeMapping GetRelationalTypeMapping(this IReadOnlyPrope
1476
1514
if ( property . DeclaringType . IsMappedToJson ( ) )
1477
1515
{
1478
1516
//JSON-splitting is not supported
1479
- //issue #28574
1517
+ //Issue #28574
1480
1518
return null ;
1481
1519
}
1482
1520
@@ -1494,20 +1532,15 @@ public static RelationalTypeMapping GetRelationalTypeMapping(this IReadOnlyPrope
1494
1532
// Using a hashset is detrimental to the perf when there are no cycles
1495
1533
for ( var i = 0 ; i < Metadata . Internal . RelationalEntityTypeExtensions . MaxEntityTypesSharingTable ; i ++ )
1496
1534
{
1497
- var entityType = rootProperty . DeclaringType as IReadOnlyEntityType ;
1498
- if ( entityType == null )
1499
- {
1500
- break ;
1501
- }
1502
-
1535
+ var entityType = rootProperty . DeclaringType . ContainingEntityType ;
1503
1536
IReadOnlyProperty ? linkedProperty = null ;
1504
- foreach ( var p in entityType
1537
+ foreach ( var principalProperty in entityType
1505
1538
. FindRowInternalForeignKeys ( storeObject )
1506
- . SelectMany ( fk => fk . PrincipalEntityType . GetProperties ( ) ) )
1539
+ . SelectMany ( static fk => fk . PrincipalEntityType . GetProperties ( ) ) )
1507
1540
{
1508
- if ( p . GetColumnName ( storeObject ) == column )
1541
+ if ( principalProperty . GetColumnName ( storeObject ) == column )
1509
1542
{
1510
- linkedProperty = p ;
1543
+ linkedProperty = principalProperty ;
1511
1544
break ;
1512
1545
}
1513
1546
}
@@ -1538,8 +1571,8 @@ public static RelationalTypeMapping GetRelationalTypeMapping(this IReadOnlyPrope
1538
1571
// Using a hashset is detrimental to the perf when there are no cycles
1539
1572
for ( var i = 0 ; i < Metadata . Internal . RelationalEntityTypeExtensions . MaxEntityTypesSharingTable ; i ++ )
1540
1573
{
1541
- var entityType = principalProperty . DeclaringType as IReadOnlyEntityType ;
1542
- var linkingRelationship = entityType ? . FindRowInternalForeignKeys ( storeObject ) . FirstOrDefault ( ) ;
1574
+ var entityType = principalProperty . DeclaringType . ContainingEntityType ;
1575
+ var linkingRelationship = entityType . FindRowInternalForeignKeys ( storeObject ) . FirstOrDefault ( ) ;
1543
1576
if ( linkingRelationship == null )
1544
1577
{
1545
1578
break ;
@@ -1566,8 +1599,8 @@ public static RelationalTypeMapping GetRelationalTypeMapping(this IReadOnlyPrope
1566
1599
// Using a hashset is detrimental to the perf when there are no cycles
1567
1600
for ( var i = 0 ; i < Metadata . Internal . RelationalEntityTypeExtensions . MaxEntityTypesSharingTable ; i ++ )
1568
1601
{
1569
- var entityType = principalProperty . DeclaringType as IReadOnlyEntityType ;
1570
- var linkingRelationship = entityType ? . FindRowInternalForeignKeys ( storeObject ) . FirstOrDefault ( ) ;
1602
+ var entityType = principalProperty . DeclaringType . ContainingEntityType ;
1603
+ var linkingRelationship = entityType . FindRowInternalForeignKeys ( storeObject ) . FirstOrDefault ( ) ;
1571
1604
if ( linkingRelationship == null )
1572
1605
{
1573
1606
break ;
@@ -1595,7 +1628,7 @@ public static RelationalTypeMapping GetRelationalTypeMapping(this IReadOnlyPrope
1595
1628
/// <param name="property">The property.</param>
1596
1629
/// <returns>The property facet overrides.</returns>
1597
1630
public static IEnumerable < IReadOnlyRelationalPropertyOverrides > GetOverrides ( this IReadOnlyProperty property )
1598
- => RelationalPropertyOverrides . Get ( property ) ?? Enumerable . Empty < IReadOnlyRelationalPropertyOverrides > ( ) ;
1631
+ => RelationalPropertyOverrides . Get ( property ) ?? [ ] ;
1599
1632
1600
1633
/// <summary>
1601
1634
/// <para>
0 commit comments