Skip to content

Commit

Permalink
Fix propagation of fixed length facet
Browse files Browse the repository at this point in the history
Fixes #18961
Fixes #14163
  • Loading branch information
ajcvickers committed Dec 30, 2019
1 parent 3bb4b38 commit 498a452
Show file tree
Hide file tree
Showing 12 changed files with 509 additions and 182 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -664,7 +664,7 @@ private void GenerateProperty(IProperty property, bool useDataAnnotations)
$"({(property.IsUnicode() == false ? "false" : "")})");
}

if (property.IsFixedLength())
if (property.IsFixedLength() != null)
{
lines.Add(
$".{nameof(RelationalPropertyBuilderExtensions.IsFixedLength)}()");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,13 +134,12 @@ public virtual TypeScaffoldingInfo FindMapping(
? (bool?)stringMapping.IsFixedLength
: null;

// Check for size
var sizedMapping = _typeMappingSource.FindMapping(
typeof(string),
null,
keyOrIndex,
unicode: mapping.IsUnicode,
fixedLength: mapping.IsFixedLength);
fixedLength: false); // Fixed length with no size is not valid

scaffoldMaxLength = sizedMapping.Size != stringMapping.Size ? stringMapping.Size : null;
}
Expand Down
14 changes: 3 additions & 11 deletions src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -360,24 +360,16 @@ private static object ConvertDefaultValue([NotNull] IProperty property, [CanBeNu
/// </summary>
/// <param name="property"> The property. </param>
/// <returns> A flag indicating if the property as capable of storing only fixed-length data, such as strings. </returns>
public static bool IsFixedLength([NotNull] this IProperty property)
=> (bool?)property[RelationalAnnotationNames.IsFixedLength] ?? GetDefaultIsFixedLength(property);

private static bool GetDefaultIsFixedLength(IProperty property)
{
var sharedTablePrincipalPrimaryKeyProperty = property.FindSharedTableRootPrimaryKeyProperty();
return sharedTablePrincipalPrimaryKeyProperty != null && IsFixedLength(sharedTablePrincipalPrimaryKeyProperty);
}
public static bool? IsFixedLength([NotNull] this IProperty property)
=> (bool?)property[RelationalAnnotationNames.IsFixedLength];

/// <summary>
/// Sets a flag indicating whether the property as capable of storing only fixed-length data, such as strings.
/// </summary>
/// <param name="property"> The property. </param>
/// <param name="fixedLength"> A value indicating whether the property is constrained to fixed length values. </param>
public static void SetIsFixedLength([NotNull] this IMutableProperty property, bool? fixedLength)
=> property.SetOrRemoveAnnotation(
RelationalAnnotationNames.IsFixedLength,
fixedLength);
=> property.SetOrRemoveAnnotation(RelationalAnnotationNames.IsFixedLength, fixedLength);

/// <summary>
/// Sets a flag indicating whether the property as capable of storing only fixed-length data, such as strings.
Expand Down
2 changes: 1 addition & 1 deletion src/EFCore.Relational/Migrations/MigrationsSqlGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1200,7 +1200,7 @@ protected virtual string GetColumnType(
{
if (operation.IsUnicode == property.IsUnicode()
&& operation.MaxLength == property.GetMaxLength()
&& (operation.IsFixedLength ?? false) == property.IsFixedLength()
&& operation.IsFixedLength == property.IsFixedLength()
&& operation.IsRowVersion == (property.IsConcurrencyToken && property.ValueGenerated == ValueGenerated.OnAddOrUpdate))
{
return Dependencies.TypeMappingSource.FindMapping(property).StoreType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -319,12 +319,21 @@ private RelationalTypeMapping FindRawMapping(RelationalTypeMappingInfo mappingIn
size = isFixedLength ? maxSize : (int?)null;
}

return size == null
? isAnsi ? _variableLengthMaxAnsiString : _variableLengthMaxUnicodeString
: new SqlServerStringTypeMapping(
unicode: !isAnsi,
size: size,
fixedLength: isFixedLength);
if (size == null)
{
return isAnsi
? isFixedLength
? _fixedLengthAnsiString
: _variableLengthMaxAnsiString
: isFixedLength
? _fixedLengthUnicodeString
: _variableLengthMaxUnicodeString;
}

return new SqlServerStringTypeMapping(
unicode: !isAnsi,
size: size,
fixedLength: isFixedLength);
}

if (clrType == typeof(byte[]))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1651,7 +1651,7 @@ public virtual void Property_unicodeness_is_stored_in_snapshot()
public virtual void Property_fixedlengthness_is_stored_in_snapshot()
{
Test(
builder => builder.Entity<EntityWithStringProperty>().Property<string>("Name").IsFixedLength(),
builder => builder.Entity<EntityWithStringProperty>().Property<string>("Name").IsFixedLength().HasMaxLength(100),
AddBoilerPlate(
GetHeading()
+ @"
Expand All @@ -1663,8 +1663,9 @@ public virtual void Property_fixedlengthness_is_stored_in_snapshot()
.HasAnnotation(""SqlServer:ValueGenerationStrategy"", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<string>(""Name"")
.HasColumnType(""nvarchar(max)"")
.IsFixedLength(true);
.HasColumnType(""nchar(100)"")
.IsFixedLength(true)
.HasMaxLength(100);
b.HasKey(""Id"");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,15 +123,16 @@ public virtual void AddColumnOperation_with_unicode_no_model()
[ConditionalFact]
public virtual void AddColumnOperation_with_fixed_length()
=> Generate(
modelBuilder => modelBuilder.Entity("Person").Property<string>("Name").IsFixedLength(),
modelBuilder => modelBuilder.Entity("Person").Property<string>("Name").HasMaxLength(100).IsFixedLength(),
new AddColumnOperation
{
Table = "Person",
Name = "Name",
ClrType = typeof(string),
IsUnicode = true,
IsNullable = true,
IsFixedLength = true
IsFixedLength = true,
MaxLength = 100
});

[ConditionalFact]
Expand All @@ -144,7 +145,8 @@ public virtual void AddColumnOperation_with_fixed_length_no_model()
ClrType = typeof(string),
IsUnicode = false,
IsNullable = true,
IsFixedLength = true
IsFixedLength = true,
MaxLength = 100
});

[ConditionalFact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public void Can_get_and_set_fixed_length()
.Property(e => e.Name)
.Metadata;

Assert.False(property.IsFixedLength());
Assert.Null(property.IsFixedLength());

property.SetIsFixedLength(true);

Expand All @@ -30,6 +30,10 @@ public void Can_get_and_set_fixed_length()
property.SetIsFixedLength(false);

Assert.False(property.IsFixedLength());

property.SetIsFixedLength(null);

Assert.Null(property.IsFixedLength());
}

[ConditionalFact]
Expand Down
20 changes: 10 additions & 10 deletions test/EFCore.Relational.Tests/Storage/RelationalTypeMapperTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -159,32 +159,32 @@ public static RelationalTypeMapping GetMapping(
=> CreateTestTypeMapper().FindMapping(property);

[ConditionalFact]
public void String_key_with_max_length_is_picked_up_by_FK()
public void String_key_with_max_fixed_length_is_picked_up_by_FK()
{
var model = CreateModel();
var mapper = CreateTestTypeMapper();

Assert.Equal(
"just_string(200)",
"just_string_fixed(200)",
GetMapping(mapper, model.FindEntityType(typeof(MyRelatedType1)).FindProperty("Id")).StoreType);

Assert.Equal(
"just_string(200)",
"just_string_fixed(200)",
GetMapping(mapper, model.FindEntityType(typeof(MyRelatedType2)).FindProperty("Relationship1Id")).StoreType);
}

[ConditionalFact]
public void Binary_key_with_max_length_is_picked_up_by_FK()
public void Binary_key_with_max_fixed_length_is_picked_up_by_FK()
{
var model = CreateModel();
var mapper = CreateTestTypeMapper();

Assert.Equal(
"just_binary(100)",
"just_binary_fixed(100)",
GetMapping(mapper, model.FindEntityType(typeof(MyRelatedType2)).FindProperty("Id")).StoreType);

Assert.Equal(
"just_binary(100)",
"just_binary_fixed(100)",
GetMapping(mapper, model.FindEntityType(typeof(MyRelatedType3)).FindProperty("Relationship1Id")).StoreType);
}

Expand Down Expand Up @@ -225,11 +225,11 @@ public void String_FK_max_length_is_preferred_if_specified()
var mapper = CreateTestTypeMapper();

Assert.Equal(
"just_string(200)",
"just_string_fixed(200)",
GetMapping(mapper, model.FindEntityType(typeof(MyRelatedType1)).FindProperty("Id")).StoreType);

Assert.Equal(
"just_string(787)",
"just_string_fixed(787)",
GetMapping(mapper, model.FindEntityType(typeof(MyRelatedType2)).FindProperty("Relationship2Id")).StoreType);
}

Expand All @@ -240,11 +240,11 @@ public void Binary_FK_max_length_is_preferred_if_specified()
var mapper = CreateTestTypeMapper();

Assert.Equal(
"just_binary(100)",
"just_binary_fixed(100)",
GetMapping(mapper, model.FindEntityType(typeof(MyRelatedType2)).FindProperty("Id")).StoreType);

Assert.Equal(
"just_binary(767)",
"just_binary_fixed(767)",
GetMapping(mapper, model.FindEntityType(typeof(MyRelatedType3)).FindProperty("Relationship2Id")).StoreType);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ protected IMutableModel CreateModel()
var builder = CreateModelBuilder();

builder.Entity<MyType>().Property(e => e.Id).HasColumnType("money");
builder.Entity<MyRelatedType1>().Property(e => e.Id).HasMaxLength(200);
builder.Entity<MyRelatedType1>().Property(e => e.Id).HasMaxLength(200).IsFixedLength();
builder.Entity<MyRelatedType1>().Property(e => e.Relationship2Id).HasColumnType("dec(6,1)");
builder.Entity<MyRelatedType2>().Property(e => e.Id).HasMaxLength(100);
builder.Entity<MyRelatedType2>().Property(e => e.Id).HasMaxLength(100).IsFixedLength();
builder.Entity<MyRelatedType2>().Property(e => e.Relationship2Id).HasMaxLength(787);
builder.Entity<MyRelatedType3>().Property(e => e.Id).IsUnicode(false);
builder.Entity<MyRelatedType3>().Property(e => e.Relationship2Id).HasMaxLength(767);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,10 @@ protected override RelationalTypeMapping FindMapping(in RelationalTypeMappingInf
}

var size = mappingInfo.Size ?? (mappingInfo.IsKeyOrIndex ? (int?)900 : null);
var isFixedLength = mappingInfo.IsFixedLength == true;

return new ByteArrayTypeMapping(
storeTypeName ?? "just_binary(" + (size == null ? "max" : size.ToString()) + ")",
storeTypeName ?? (isFixedLength ? "just_binary_fixed(" : "just_binary(") + (size == null ? "max" : size.ToString()) + ")",
DbType.Binary,
size);
}
Expand Down
Loading

0 comments on commit 498a452

Please sign in to comment.