dotnet / dotnet/EntityFramework.Docs

Document that value comparers must handle nulls

Open
#4,168 1 comment 0 reactions 0 assignees View on GitHub
area-value-conversions
Dominant language
Mermaid
Stars
1.7k
Forks
2k
Avg merge
7d 23h
Merged PRs (30d)
16

Description

## File a bug

### Include your code

Consider the following example which worked in EF Core 6 but throws in EF Core 7:

```C#
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Microsoft.Extensions.DependencyInjection;
using System.Text.Json;

Console.WriteLine("Hello, World!");

var services = new ServiceCollection()
.AddDbContext(options => options.UseSqlServer(connectionString: "NotImportant"))
.BuildServiceProvider();

var db = services.GetRequiredService();

db.Set().Add(new Model());

class Model
{
public int Id { get; set; }
public List Strings { get; set; } = new List();
}

class AppContext : DbContext
{
public AppContext(DbContextOptions options) : base(options)
{
}

public DbSet Models { get; init; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity().Property(x => x.Strings).HasConversion(JsonValueConverter>.Default, ListValueComparer.Default).IsRequired().HasDefaultValueSql("[]");
}
}

public class JsonValueConverter : ValueConverter
{
public static JsonValueConverter Default { get; } = new JsonValueConverter();

public JsonValueConverter(JsonSerializerOptions? options = null) : base(
convertToProviderExpression: x => JsonSerializer.Serialize(x, options),
convertFromProviderExpression: x => JsonSerializer.Deserialize(x, options))
{
}
}

public class ListValueComparer : ValueComparer>
{
public static readonly ListValueComparer Default = new();

public ListValueComparer() : base(
equalsExpression: (a, b) => EqualsFn(a, b),
hashCodeExpression: x => x.Aggregate(x.Count, (a, v) => HashCode.Combine(a, v.GetHashCode())),
snapshotExpression: x => new List(x))
{
}

static bool EqualsFn(List a, List b)
{
// This line throws in v7 because b is now "null for an empty list" instead of being an empty list.
return Enumerable.SequenceEqual(a, b);
}
}
```

In EF Core 6 the EqualsFn was never called with `b = null` but this is the case now EF Core 7 even when `HasDefaultValueSql("[]")` should have set a default value to an empty list.

### Include provider and version information

EF Core version: 7.0.0
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 7.0
Operating system:
IDE: Visual Studio 2022 17.4

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.