Skip to content

Commit

Permalink
Make filtered unique index update dependencies soft
Browse files Browse the repository at this point in the history
Fixes #28065
  • Loading branch information
AndriySvyryd committed Aug 30, 2022
1 parent 99f03c7 commit 0675a89
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,7 @@ public static void SetDatabaseName(this IMutableIndex index, string? name)
/// <param name="index">The index.</param>
/// <returns>The index filter expression.</returns>
public static string? GetFilter(this IReadOnlyIndex index)
=> (index is RuntimeIndex)
? throw new InvalidOperationException(CoreStrings.RuntimeModelMissingData)
: (string?)index.FindAnnotation(RelationalAnnotationNames.Filter)?.Value;
=> (string?)index.FindAnnotation(RelationalAnnotationNames.Filter)?.Value;

/// <summary>
/// Returns the index filter expression.
Expand All @@ -120,11 +118,6 @@ public static void SetDatabaseName(this IMutableIndex index, string? name)
/// <returns>The index filter expression.</returns>
public static string? GetFilter(this IReadOnlyIndex index, in StoreObjectIdentifier storeObject)
{
if (index is RuntimeIndex)
{
throw new InvalidOperationException(CoreStrings.RuntimeModelMissingData);
}

var annotation = index.FindAnnotation(RelationalAnnotationNames.Filter);
if (annotation != null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,10 @@ protected override void ProcessIndexAnnotations(
{
base.ProcessIndexAnnotations(annotations, index, runtimeIndex, runtime);

annotations.Remove(runtime ? RelationalAnnotationNames.TableIndexMappings : RelationalAnnotationNames.Filter);
if (runtime)
{
annotations.Remove(RelationalAnnotationNames.TableIndexMappings);
}
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,11 @@ public virtual IReadOnlyList<List<IReadOnlyModificationCommand>> TopologicalSort

AddSameTableEdges(_modificationCommandGraph);

return _modificationCommandGraph.BatchingTopologicalSort(static (_, _, edges) => edges.All(e => e is ITable), FormatCycle);
return _modificationCommandGraph.BatchingTopologicalSort(
static (_, _, edges) => edges.All(e =>
e is ITable
|| (e is ITableIndex index && index.Filter != null)),
FormatCycle);
}

private string FormatCycle(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1870,9 +1870,7 @@ public static void CreateAnnotations(RuntimeEntityType runtimeEntityType)
Assert.Equal("AlternateIndex", alternateIndex.Name);
Assert.Equal("AIX", alternateIndex.GetDatabaseName());
Assert.Null(alternateIndex[RelationalAnnotationNames.Filter]);
Assert.Equal(
CoreStrings.RuntimeModelMissingData,
Assert.Throws<InvalidOperationException>(() => alternateIndex.GetFilter()).Message);
Assert.Null(alternateIndex.GetFilter());
Assert.Equal(new[] { compositeIndex, alternateIndex }, principalAlternateId.GetContainingIndexes());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,45 @@ public virtual void Save_with_shared_foreign_key()
});
}

[ConditionalFact]
public virtual void Swap_filtered_unique_index_values()
{
var productId1 = new Guid("984ade3c-2f7b-4651-a351-642e92ab7146");
var productId2 = new Guid("0edc9136-7eed-463b-9b97-bdb9648ab877");

ExecuteWithStrategyInTransaction(
context =>
{
var product1 = context.Products.Find(productId1)!;
var product2 = context.Products.Find(productId2)!;
product2.Name = null;
product2.Price = product1.Price;
context.SaveChanges();
},
context =>
{
var product1 = context.Products.Find(productId1)!;
var product2 = context.Products.Find(productId2)!;
product2.Name = product1.Name;
product1.Name = null;
context.SaveChanges();
},
context =>
{
var product1 = context.Products.Find(productId1)!;
var product2 = context.Products.Find(productId2)!;
Assert.Equal(1.49M, product1.Price);
Assert.Null(product1.Name);
Assert.Equal(1.49M, product2.Price);
Assert.Equal("Apple Cider", product2.Name);
});
}

[ConditionalFact]
public abstract void Identifiers_are_generated_correctly();

Expand All @@ -133,6 +172,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con
modelBuilder.Entity<ProductTableWithView>().HasBaseType((string)null).ToView("ProductView").ToTable("ProductTable");
modelBuilder.Entity<ProductTableView>().HasBaseType((string)null).ToView("ProductTable");

modelBuilder.Entity<Product>().HasIndex(p => new { p.Name, p.Price }).IsUnique().HasFilter("Name IS NOT NULL");

modelBuilder
.Entity<
LoginEntityTypeWithAnExtremelyLongAndOverlyConvolutedNameThatIsUsedToVerifyThatTheStoreIdentifierGenerationLengthLimitIsWorkingCorrectlyDetails
Expand Down

0 comments on commit 0675a89

Please sign in to comment.