Skip to content

Conversion is not consistent across some methods for InMemory database #30810

@oleggolovkov

Description

@oleggolovkov

Some operations do not respect the HasConversion configuration when used with in-memory DB

See the following code where the same entity is retrieved from DB using 2 methods:
a) fetching all table data into array and using Linq-to-Objects over it
b) using EF query
One of the approaches is able to correctly locate the data while the other one is not. Removing the .HasConversion part causes both approaches to behave correctly the same way

Code to reproduce

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

await using var ctx = new TodoDb();
ctx.Todos.Add(new Todo { Id = TodoDb.DefaultId });
await ctx.SaveChangesAsync();

var todos = await ctx.Todos.ToArrayAsync();

var todoFromArray = todos.FirstOrDefault(t => t.Id == TodoDb.DefaultId);
Console.WriteLine(todoFromArray is not null); // true

var todoFromDb = ctx.Todos.FirstOrDefault(t => t.Id == TodoDb.DefaultId);
Console.WriteLine(todoFromDb is not null); // false

class TodoDb : DbContext
{
    public static Guid DefaultId = Guid.Parse("2965109F-B866-4B41-A600-AF570AC1E4C7");
    public DbSet<Todo> Todos => Set<Todo>();

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.ApplyConfiguration(new TodoConfiguration());
        base.OnModelCreating(modelBuilder);
    }
    
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    { 
        optionsBuilder.UseInMemoryDatabase("TodoList");
    }

    private static class DbGuidConverter
    {
        public static byte[] GuidToBinary(Guid guid)
        {
            var bytes = guid.ToByteArray();
            Rotate(bytes);
            return bytes;
        }

        public static Guid BinaryToGuid(byte[] binary)
        {
            Rotate(binary);
            return new Guid(binary);
        }
        
        static void Rotate(Span<byte> bytes)
        {
            Swap(bytes,0,3);
            Swap(bytes,1,2);
            Swap(bytes,4,5);
            Swap(bytes,6,7);
        }
        
        static void Swap(Span<byte> source, int a, int b) => (source[a], source[b]) = (source[b], source[a]);
    }
    
    internal class TodoConfiguration : IEntityTypeConfiguration<Todo>
    {
        public void Configure(EntityTypeBuilder<Todo> builder)
        {
            builder.HasKey(x => x.Id);

            builder
                .Property(x => x.Id)
                .HasConversion(id => DbGuidConverter.GuidToBinary(id), blob => DbGuidConverter.BinaryToGuid(blob));
        }
    }
}

public class Todo
{
    public Guid Id { get; set; }
}

Complete csproj file:

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net7.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
    </PropertyGroup>

    <ItemGroup>
      <PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.5" />
    </ItemGroup>

</Project>

Activity

ajcvickers

ajcvickers commented on May 2, 2023

@ajcvickers
Contributor

@oleggolovkov Have you tried with the latest EF8 preview? We already fixed some issues in this area.

oleggolovkov

oleggolovkov commented on May 2, 2023

@oleggolovkov
Author

@ajcvickers I can see that behavior is the same using <PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.0-preview.3.23174.2" />

ajcvickers

ajcvickers commented on May 2, 2023

@ajcvickers
Contributor

Thanks. We will investigate.

ajcvickers

ajcvickers commented on May 3, 2023

@ajcvickers
Contributor

Note for triage: looks like the in-memory database is not doing deep comparisons of the bytes after the conversion.

added this to the Backlog milestone on May 4, 2023
added theissue type on Jun 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @oleggolovkov@ajcvickers@roji@cincuranet

        Issue actions

          Conversion is not consistent across some methods for InMemory database · Issue #30810 · dotnet/efcore