Skip to content
Open
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 @@ -49,11 +49,28 @@ protected override void ProcessSinglePropertyJsonUpdate(ref ColumnModificationPa
var propertyProviderClrType = (mapping.Converter?.ProviderClrType ?? property.ClrType).UnwrapNullableType();
var value = parameters.Value;

// JSON-compatible non-string values (bool, numeric, null) are sent directly as non-string parameters.
if (value is null
|| ((propertyProviderClrType == typeof(bool)
// A null value is sent as a NULL parameter. JSON_MODIFY rejects parameters whose type can't be implicitly
// converted to nvarchar (e.g. date/time types), even when the value itself is null. Since the value is null the
// parameter type doesn't affect the result, so keep the property's mapping only for types that JSON_MODIFY
// accepts directly (string, bool, numeric) and otherwise fall back to a string mapping.
if (value is null)
{
parameters = parameters with
{
TypeMapping = propertyProviderClrType == typeof(string)
|| propertyProviderClrType == typeof(bool)
|| propertyProviderClrType.IsNumeric()
? mapping
: SqlServerStringTypeMapping.UnicodeDefault
};

return;
}

// JSON-compatible non-string values (bool, numeric) are sent directly as non-string parameters.
if ((propertyProviderClrType == typeof(bool)
|| propertyProviderClrType.IsNumeric())
&& !property.IsPrimitiveCollection))
&& !property.IsPrimitiveCollection)
{
parameters = parameters with { Value = value, TypeMapping = mapping };

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1234,6 +1234,50 @@ public virtual Task Edit_single_property_nullable_int32_set_to_null()
Assert.Null(result.Collection[0].TestNullableInt32);
});

[Fact]
public virtual Task Edit_single_property_nullable_datetime_set_to_null()
=> TestHelpers.ExecuteWithStrategyInTransactionAsync(
CreateContext,
UseTransaction,
async context =>
{
var query = await context.JsonEntitiesAllTypes.ToListAsync();
var entity = query.Single(x => x.Id == 1);
entity.Reference.TestNullableDateTime = null;
entity.Collection[0].TestNullableDateTime = null;

ClearLog();
await context.SaveChangesAsync();
},
async context =>
{
var result = await context.Set<JsonEntityAllTypes>().SingleAsync(x => x.Id == 1);
Assert.Null(result.Reference.TestNullableDateTime);
Assert.Null(result.Collection[0].TestNullableDateTime);
});

[Fact]
public virtual Task Edit_single_property_nullable_dateonly_set_to_null()
=> TestHelpers.ExecuteWithStrategyInTransactionAsync(
CreateContext,
UseTransaction,
async context =>
{
var query = await context.JsonEntitiesAllTypes.ToListAsync();
var entity = query.Single(x => x.Id == 1);
entity.Reference.TestNullableDateOnly = null;
entity.Collection[0].TestNullableDateOnly = null;

ClearLog();
await context.SaveChangesAsync();
},
async context =>
{
var result = await context.Set<JsonEntityAllTypes>().SingleAsync(x => x.Id == 1);
Assert.Null(result.Reference.TestNullableDateOnly);
Assert.Null(result.Collection[0].TestNullableDateOnly);
});

[Fact]
public virtual Task Edit_single_property_enum()
=> TestHelpers.ExecuteWithStrategyInTransactionAsync(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,8 @@ public static void AssertAllTypes(JsonOwnedAllTypes expected, JsonOwnedAllTypes
Assert.Equal(expected.TestUnsignedInt32, actual.TestUnsignedInt32);
Assert.Equal(expected.TestUnsignedInt64, actual.TestUnsignedInt64);
Assert.Equal(expected.TestNullableInt32, actual.TestNullableInt32);
Assert.Equal(expected.TestNullableDateTime, actual.TestNullableDateTime);
Assert.Equal(expected.TestNullableDateOnly, actual.TestNullableDateOnly);
Assert.Equal(expected.TestEnum, actual.TestEnum);
Assert.Equal(expected.TestEnumWithIntConverter, actual.TestEnumWithIntConverter);
Assert.Equal(expected.TestNullableEnum, actual.TestNullableEnum);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ public class JsonOwnedAllTypes
public char TestCharacter { get; set; }
public sbyte TestSignedByte { get; set; }
public int? TestNullableInt32 { get; set; }
public DateTime? TestNullableDateTime { get; set; }
public DateOnly? TestNullableDateOnly { get; set; }
public JsonEnum TestEnum { get; set; }
public JsonEnum TestEnumWithIntConverter { get; set; }
public JsonEnum? TestNullableEnum { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,8 @@ public static IReadOnlyList<JsonEntityAllTypes> CreateJsonEntitiesAllTypes()
TestCharacter = 'a',
TestSignedByte = -128,
TestNullableInt32 = 78,
TestNullableDateTime = new DateTime(2000, 1, 1, 12, 34, 56),
TestNullableDateOnly = new DateOnly(2023, 10, 10),
TestEnum = JsonEnum.One,
TestEnumWithIntConverter = JsonEnum.Two,
TestNullableEnum = JsonEnum.One,
Expand Down Expand Up @@ -985,6 +987,8 @@ public static IReadOnlyList<JsonEntityAllTypes> CreateJsonEntitiesAllTypes()
TestCharacter = 'h',
TestSignedByte = -18,
TestNullableInt32 = 90,
TestNullableDateTime = new DateTime(2100, 11, 11, 12, 34, 56),
TestNullableDateOnly = new DateOnly(2323, 4, 3),
TestEnum = JsonEnum.One,
TestEnumWithIntConverter = JsonEnum.Two,
TestNullableEnum = JsonEnum.One,
Expand Down
Loading
Loading