Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ If you are not sure, do not guess, just tell that you don't know or ask clarifyi
- Use nullable reference types
- Use proper null-checking patterns
- Use the null-conditional operator (`?.`) and null-coalescing operator (`??`) when appropriate
- Don't disable nullability with a preprocessor directive (`#nullable disable`)

## Architecture and Design Patterns

Expand Down
565 changes: 308 additions & 257 deletions src/EFCore.Cosmos/Infrastructure/Internal/CosmosModelValidator.cs

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions src/EFCore.Relational/Diagnostics/RelationalEventId.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ private enum Id
// Model validation events
ModelValidationKeyDefaultValueWarning = CoreEventId.RelationalBaseId + 600,
BoolWithDefaultWarning,
AllIndexPropertiesNotToMappedToAnyTable,
AllIndexPropertiesNotMappedToAnyTable,
IndexPropertiesBothMappedAndNotMappedToTable,
IndexPropertiesMappedToNonOverlappingTables,
ForeignKeyPropertiesMappedToUnrelatedTables,
Expand Down Expand Up @@ -914,8 +914,8 @@ private static EventId MakeValidationId(Id id)
/// This event uses the <see cref="IndexEventData" /> payload when used with a <see cref="DiagnosticSource" />.
/// </para>
/// </remarks>
public static readonly EventId AllIndexPropertiesNotToMappedToAnyTable =
MakeValidationId(Id.AllIndexPropertiesNotToMappedToAnyTable);
public static readonly EventId AllIndexPropertiesNotMappedToAnyTable =
MakeValidationId(Id.AllIndexPropertiesNotMappedToAnyTable);

/// <summary>
/// An index specifies properties some of which are mapped and some of which are not mapped to a column in a table.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2868,19 +2868,19 @@ private static string BatchSmallerThanMinBatchSize(EventDefinitionBase definitio
}

/// <summary>
/// Logs the <see cref="RelationalEventId.AllIndexPropertiesNotToMappedToAnyTable" /> event.
/// Logs the <see cref="RelationalEventId.AllIndexPropertiesNotMappedToAnyTable" /> event.
/// </summary>
/// <param name="diagnostics">The diagnostics logger to use.</param>
/// <param name="entityType">The entity type on which the index is defined.</param>
/// <param name="index">The index on the entity type.</param>
public static void AllIndexPropertiesNotToMappedToAnyTable(
public static void AllIndexPropertiesNotMappedToAnyTable(
this IDiagnosticsLogger<DbLoggerCategory.Model.Validation> diagnostics,
IEntityType entityType,
IIndex index)
{
if (index.Name == null)
{
var definition = RelationalResources.LogUnnamedIndexAllPropertiesNotToMappedToAnyTable(diagnostics);
var definition = RelationalResources.LogUnnamedIndexAllPropertiesNotMappedToAnyTable(diagnostics);

if (diagnostics.ShouldLog(definition))
{
Expand All @@ -2904,7 +2904,7 @@ public static void AllIndexPropertiesNotToMappedToAnyTable(
}
else
{
var definition = RelationalResources.LogNamedIndexAllPropertiesNotToMappedToAnyTable(diagnostics);
var definition = RelationalResources.LogNamedIndexAllPropertiesNotMappedToAnyTable(diagnostics);

if (diagnostics.ShouldLog(definition))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ public abstract class RelationalLoggingDefinitions : LoggingDefinitions
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
[EntityFrameworkInternal]
public EventDefinitionBase? LogNamedIndexAllPropertiesNotToMappedToAnyTable;
public EventDefinitionBase? LogNamedIndexAllPropertiesNotMappedToAnyTable;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand All @@ -527,7 +527,7 @@ public abstract class RelationalLoggingDefinitions : LoggingDefinitions
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
[EntityFrameworkInternal]
public EventDefinitionBase? LogUnnamedIndexAllPropertiesNotToMappedToAnyTable;
public EventDefinitionBase? LogUnnamedIndexAllPropertiesNotMappedToAnyTable;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down
70 changes: 68 additions & 2 deletions src/EFCore.Relational/Extensions/RelationalIndexExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,20 @@ public static class RelationalIndexExtensions
/// <param name="storeObject">The identifier of the store object.</param>
/// <returns>The name of the index in the database.</returns>
public static string? GetDatabaseName(this IReadOnlyIndex index, in StoreObjectIdentifier storeObject)
=> index.GetDatabaseName(storeObject, null);
{
if (storeObject.StoreObjectType != StoreObjectType.Table)
{
return null;
}

var defaultName = index.GetDefaultDatabaseName(storeObject);
var annotation = index.FindAnnotation(RelationalAnnotationNames.Name);
return annotation != null && defaultName != null
? (string?)annotation.Value
: defaultName != null
? index.Name ?? defaultName
: defaultName;
}

/// <summary>
/// Returns the default name that would be used for this index.
Expand Down Expand Up @@ -67,7 +80,60 @@ public static class RelationalIndexExtensions
/// <param name="storeObject">The identifier of the store object.</param>
/// <returns>The default name that would be used for this index.</returns>
public static string? GetDefaultDatabaseName(this IReadOnlyIndex index, in StoreObjectIdentifier storeObject)
=> index.GetDefaultDatabaseName(storeObject, null);
{
if (storeObject.StoreObjectType != StoreObjectType.Table)
{
return null;
}

var columnNames = index.Properties.GetColumnNames(storeObject);
if (columnNames == null)
{
return null;
}

var rootIndex = index;

// Limit traversal to avoid getting stuck in a cycle (validation will throw for these later)
// Using a hashset is detrimental to the perf when there are no cycles
for (var i = 0; i < Metadata.Internal.RelationalEntityTypeExtensions.MaxEntityTypesSharingTable; i++)
{
IReadOnlyIndex? linkedIndex = null;
foreach (var otherIndex in rootIndex.DeclaringEntityType
.FindRowInternalForeignKeys(storeObject)
.SelectMany(fk => fk.PrincipalEntityType.GetIndexes()))
{
var otherColumnNames = otherIndex.Properties.GetColumnNames(storeObject);
if ((otherColumnNames != null)
&& otherColumnNames.SequenceEqual(columnNames))
{
linkedIndex = otherIndex;
break;
}
}

if (linkedIndex == null)
{
break;
}

rootIndex = linkedIndex;
}

if (rootIndex != index)
{
return rootIndex.GetDatabaseName(storeObject);
}

var baseName = new StringBuilder()
.Append("IX_")
.Append(storeObject.Name)
.Append('_')
.AppendJoin(columnNames, "_")
.ToString();

return Uniquifier.Truncate(baseName, index.DeclaringEntityType.Model.GetMaxIdentifierLength());
}

/// <summary>
/// Sets the name of the index in the database.
Expand Down
Loading
Loading