Skip to content

Entity mapped to JSON returns different byte[] when not the whole entity is projected #33435

@frencsi

Description

@frencsi

Sample code

var user = new User
{
    Vault = new UserVault
    {
        PasswordHash = RandomNumberGenerator.GetBytes(64)
    }
};

await using var context = new TestDbContext();
await context.Users.AddAsync(user);
await context.SaveChangesAsync();

var vaultProjection = await context.Users
    .AsNoTracking()
    .Where(x => x.Id == user.Id)
    .Select(x => x.Vault)
    .FirstAsync();

var passwordHashProjection = await context.Users
    .Where(x => x.Id == user.Id)
    .Select(x => x.Vault.PasswordHash)
    .FirstAsync();

var customProjection = await context.Users
    .Where(x => x.Id == user.Id)
    .Select(x => new { PasswordHash = x.Vault.PasswordHash })
    .FirstAsync();

var c1 = vaultProjection.PasswordHash.SequenceEqual(user.Vault.PasswordHash);

var c2 = passwordHashProjection.SequenceEqual(user.Vault.PasswordHash);

var c3 = customProjection.PasswordHash.SequenceEqual(user.Vault.PasswordHash);

Console.WriteLine($"c1:{c1}\nc2:{c2}\nc3:{c3}");

public class TestDbContext : DbContext
{
    public DbSet<User> Users => Set<User>();

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder
            .UseSqlServer("Server=localhost;Database=test;User=SA;Password=Password123@;Encrypt=false")
            .LogTo(Console.WriteLine, LogLevel.Information)
            .EnableSensitiveDataLogging();

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>().HasKey(user => user.Id);

        modelBuilder.Entity<User>().OwnsOne(user => user.Vault).ToJson();
    }
}

public class User
{
    public int Id { get; set; }

    public UserVault Vault { get; set; }
}

public class UserVault
{
    public byte[] PasswordHash { get; set; }
}

Generated queries

1.:

SELECT TOP(1) [u].[Vault], [u].[Id]
FROM [Users] AS [u]
WHERE [u].[Id] = @__user_Id_0

2.:

SELECT TOP(1) CAST(JSON_VALUE([u].[Vault], '$.PasswordHash') AS varbinary(max))
FROM [Users] AS [u]
WHERE [u].[Id] = @__user_Id_0

3.:

SELECT TOP(1) CAST(JSON_VALUE([u].[Vault], '$.PasswordHash') AS varbinary(max)) AS [PasswordHash]
FROM [Users] AS [u]
WHERE [u].[Id] = @__user_Id_0

Results

c1: true
c2: false
c3: false

Second & third query returns a larger completely different byte array.

Versions

EF Core version: 9.0.0-preview.2.24128.4
Database provider: Microsoft.EntityFrameworkCore.SqlServer version: 9.0.0-preview.2.24128.4
.NET version: 9.0.100-preview.2

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions