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
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ protected virtual IEnumerable<MigrationOperation> Diff(
var sourceMigrationsAnnotations = source.GetAnnotations();
var targetMigrationsAnnotations = target.GetAnnotations();

if (source.Comment != target.Comment
if (!MultilineEquals(source.Comment, target.Comment)
|| HasDifferences(sourceMigrationsAnnotations, targetMigrationsAnnotations))
{
var alterTableOperation = new AlterTableOperation
Expand Down Expand Up @@ -986,11 +986,11 @@ private static bool ColumnStructureEquals(IColumn source, IColumn target)
&& source.MaxLength == target.MaxLength
&& source.IsFixedLength == target.IsFixedLength
&& source.Collation == target.Collation
&& source.Comment == target.Comment
&& MultilineEquals(source.Comment, target.Comment)
&& source.IsStored == target.IsStored
&& source.ComputedColumnSql == target.ComputedColumnSql
&& MultilineEquals(source.ComputedColumnSql, target.ComputedColumnSql)
&& Equals(sourceDefault, targetDefault)
&& source.DefaultValueSql == target.DefaultValueSql;
&& MultilineEquals(source.DefaultValueSql, target.DefaultValueSql);
}

private static bool EntityTypePathEquals(ITypeBase source, ITypeBase target, DiffContext diffContext)
Expand Down Expand Up @@ -1079,12 +1079,12 @@ protected virtual IEnumerable<MigrationOperation> Diff(

if (isNullableChanged
|| columnTypeChanged
|| source.DefaultValueSql != target.DefaultValueSql
|| source.ComputedColumnSql != target.ComputedColumnSql
|| !MultilineEquals(source.DefaultValueSql, target.DefaultValueSql)
|| !MultilineEquals(source.ComputedColumnSql, target.ComputedColumnSql)
|| source.IsStored != target.IsStored
|| sourceDefault?.GetType() != targetDefault?.GetType()
|| (sourceDefault != DBNull.Value && !target.ProviderValueComparer.Equals(sourceDefault, targetDefault))
|| source.Comment != target.Comment
|| !MultilineEquals(source.Comment, target.Comment)
|| source.Collation != target.Collation
|| source.Order != target.Order
|| HasDifferences(sourceMigrationsAnnotations, targetMigrationsAnnotations))
Expand Down Expand Up @@ -1507,7 +1507,7 @@ private bool IndexStructureEquals(ITableIndex source, ITableIndex target, DiffCo
|| (source.IsDescending is not null
&& target.IsDescending is not null
&& source.IsDescending.SequenceEqual(target.IsDescending)))
&& source.Filter == target.Filter
&& MultilineEquals(source.Filter, target.Filter)
&& !HasDifferences(source.GetAnnotations(), target.GetAnnotations())
&& source.Columns.Select(p => p.Name).SequenceEqual(
target.Columns.Select(p => diffContext.FindSource(p)?.Name));
Expand Down Expand Up @@ -1600,7 +1600,7 @@ protected virtual IEnumerable<MigrationOperation> Diff(
Remove,
(s, t, c) => c.FindTable(s.EntityType) == c.FindSource(c.FindTable(t.EntityType))
&& string.Equals(s.Name, t.Name, StringComparison.OrdinalIgnoreCase)
&& string.Equals(s.Sql, t.Sql, StringComparison.OrdinalIgnoreCase));
&& MultilineEquals(s.Sql, t.Sql));

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down Expand Up @@ -2481,7 +2481,7 @@ protected virtual bool HasDifferences(IEnumerable<IAnnotation> source, IEnumerab
foreach (var annotation in source)
{
var index = unmatched.FindIndex(a
=> a.Name == annotation.Name && StructuralComparisons.StructuralEqualityComparer.Equals(a.Value, annotation.Value));
=> a.Name == annotation.Name && AnnotationValuesEqual(a, annotation));
if (index == -1)
{
return true;
Expand All @@ -2491,8 +2491,19 @@ protected virtual bool HasDifferences(IEnumerable<IAnnotation> source, IEnumerab
}

return unmatched.Count != 0;

static bool AnnotationValuesEqual(IAnnotation left, IAnnotation right)
=> left.Value is string leftString && right.Value is string rightString
? MultilineEquals(leftString, rightString)
: StructuralComparisons.StructuralEqualityComparer.Equals(left.Value, right.Value);
}

private static bool MultilineEquals(string? sourceString, string? targetString, StringComparison comparisonType = StringComparison.Ordinal)
=> ReferenceEquals(sourceString, targetString)
|| (sourceString is not null
&& targetString is not null
&& string.Equals(sourceString.ReplaceLineEndings(), targetString.ReplaceLineEndings(), comparisonType));

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
Expand Down
2 changes: 1 addition & 1 deletion src/EFCore/ChangeTracking/PropertyValues.cs
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ internal virtual IComplexProperty CheckCollection(IComplexProperty complexProper
/// <typeparam name="TValue">The type of the property.</typeparam>
/// <param name="propertyName">The property name.</param>
/// <param name="value">The property value if any.</param>
/// <returns>True if the property exists, otherwise false.</returns>
/// <returns><see langword="true" /> if the property exists, otherwise <see langword="false" />.</returns>
public virtual bool TryGetValue<TValue>(string propertyName, out TValue value)
{
var property = Properties.FirstOrDefault(p => p.Name == propertyName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12318,6 +12318,127 @@ public void Model_differ_does_not_detect_entity_type_mapped_to_TVF()
result => Assert.Equal(0, result.Count),
skipSourceConventions: true);

[ConditionalFact]
public void Model_differ_ignores_newline_differences_in_DefaultValueSql()
=> Execute(
source => source.Entity("Cat", x => x.Property<string>("Meow").HasDefaultValueSql("SELECT\r\n'test'")),
target => target.Entity("Cat", x => x.Property<string>("Meow").HasDefaultValueSql("SELECT\n'test'")),
result => Assert.Empty(result));

[ConditionalFact]
public void Model_differ_ignores_newline_differences_in_ComputedColumnSql()
=> Execute(
source => source.Entity("Cat", x => x.Property<string>("Meow").HasComputedColumnSql("UPPER(\r\nName)")),
target => target.Entity("Cat", x => x.Property<string>("Meow").HasComputedColumnSql("UPPER(\nName)")),
result => Assert.Empty(result));

[ConditionalFact]
public void Model_differ_ignores_newline_differences_in_index_filter()
=> Execute(
source => source.Entity("Cat", x =>
{
x.Property<string>("Name");
x.HasIndex("Name").HasFilter("Name IS NOT\r\nNULL");
}),
target => target.Entity("Cat", x =>
{
x.Property<string>("Name");
x.HasIndex("Name").HasFilter("Name IS NOT\nNULL");
}),
result => Assert.Empty(result));

[ConditionalFact]
public void Model_differ_ignores_newline_differences_in_check_constraint()
=> Execute(
source => source.Entity("Cat", x =>
{
x.Property<int>("Age");
x.ToTable(t => t.HasCheckConstraint("CK_Cat_Age", "Age >\r\n0"));
}),
target => target.Entity("Cat", x =>
{
x.Property<int>("Age");
x.ToTable(t => t.HasCheckConstraint("CK_Cat_Age", "Age >\n0"));
}),
result => Assert.Empty(result));

[ConditionalFact]
public void Model_differ_ignores_carriage_return_differences_in_DefaultValueSql()
=> Execute(
source => source.Entity("Cat", x => x.Property<string>("Meow").HasDefaultValueSql("SELECT\r'test'")),
target => target.Entity("Cat", x => x.Property<string>("Meow").HasDefaultValueSql("SELECT\n'test'")),
result => Assert.Empty(result));

[ConditionalFact]
public void Model_differ_ignores_complex_newline_differences_in_ComputedColumnSql()
=> Execute(
source => source.Entity("Cat", x => x.Property<string>("Meow").HasComputedColumnSql("CASE\r\nWHEN Age > 5\r\nTHEN 'Old'\r\nELSE 'Young'\r\nEND")),
target => target.Entity("Cat", x => x.Property<string>("Meow").HasComputedColumnSql("CASE\nWHEN Age > 5\nTHEN 'Old'\nELSE 'Young'\nEND")),
result => Assert.Empty(result));

[ConditionalFact]
public void Model_differ_ignores_newline_differences_in_table_comments()
=> Execute(
source => source.Entity("Cat", x => x.ToTable(t => t.HasComment("Table for storing\r\ncat information"))),
target => target.Entity("Cat", x => x.ToTable(t => t.HasComment("Table for storing\ncat information"))),
result => Assert.Empty(result));

[ConditionalFact]
public void Model_differ_ignores_newline_differences_in_column_comments()
=> Execute(
source => source.Entity("Cat", x => x.Property<string>("Name").HasComment("Cat name\r\nfield")),
target => target.Entity("Cat", x => x.Property<string>("Name").HasComment("Cat name\nfield")),
result => Assert.Empty(result));

[ConditionalFact]
public void Model_differ_ignores_newline_differences_in_DefaultValueSql_annotations()
=> Execute(
source => source.Entity("Cat", x => x.Property<string>("Name").HasAnnotation("Relational:DefaultValueSql", "SELECT\r\n'test'")),
target => target.Entity("Cat", x => x.Property<string>("Name").HasAnnotation("Relational:DefaultValueSql", "SELECT\n'test'")),
result => Assert.Empty(result));

[ConditionalFact]
public void Model_differ_ignores_newline_differences_in_ComputedColumnSql_annotations()
=> Execute(
source => source.Entity("Cat", x => x.Property<string>("Name").HasAnnotation("Relational:ComputedColumnSql", "UPPER(\r\nName)")),
target => target.Entity("Cat", x => x.Property<string>("Name").HasAnnotation("Relational:ComputedColumnSql", "UPPER(\nName)")),
result => Assert.Empty(result));

[ConditionalFact]
public void Model_differ_ignores_newline_differences_in_Comment_annotations()
=> Execute(
source => source.Entity("Cat", x => x.Property<string>("Name").HasAnnotation("Relational:Comment", "Multi-line\r\ncomment")),
target => target.Entity("Cat", x => x.Property<string>("Name").HasAnnotation("Relational:Comment", "Multi-line\ncomment")),
result => Assert.Empty(result));

[ConditionalFact]
public void Model_differ_ignores_newline_differences_in_ViewDefinitionSql_annotations()
=> Execute(
source => source.Entity("Cat", x => x.HasAnnotation("Relational:ViewDefinitionSql", "SELECT Id,\r\nName FROM Cats")),
target => target.Entity("Cat", x => x.HasAnnotation("Relational:ViewDefinitionSql", "SELECT Id,\nName FROM Cats")),
result => Assert.Empty(result));

[ConditionalFact]
public void Model_differ_ignores_newline_differences_in_Filter_annotations()
=> Execute(
source => source.Entity("Cat", x => x.Property<string>("Name").HasAnnotation("Relational:Filter", "Name IS NOT\r\nNULL")),
target => target.Entity("Cat", x => x.Property<string>("Name").HasAnnotation("Relational:Filter", "Name IS NOT\nNULL")),
result => Assert.Empty(result));

[ConditionalFact]
public void Model_differ_detects_actual_annotation_sql_changes()
=> Execute(
source => source.Entity("Cat", x => x.Property<string>("Name").HasAnnotation("Relational:DefaultValueSql", "SELECT 'old'")),
target => target.Entity("Cat", x => x.Property<string>("Name").HasAnnotation("Relational:DefaultValueSql", "SELECT 'new'")),
result => Assert.Single(result));

[ConditionalFact]
public void Model_differ_ignores_newline_differences_in_non_relational_annotations()
=> Execute(
source => source.Entity("Cat", x => x.Property<string>("Name").HasAnnotation("CustomAnnotation", "Value with\r\nnewlines")),
target => target.Entity("Cat", x => x.Property<string>("Name").HasAnnotation("CustomAnnotation", "Value with\nnewlines")),
result => Assert.Empty(result));

protected override TestHelpers TestHelpers
=> FakeRelationalTestHelpers.Instance;
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public void Dispose()
=> _disposed = true;

public static string NormalizeLineEndings(string expectedString)
=> expectedString.Replace("\r", string.Empty).Replace("\n", Environment.NewLine);
=> expectedString.ReplaceLineEndings();

protected class ListLogger : ILogger
{
Expand Down
Loading