dotnet / efcore

EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
https://docs.microsoft.com/ef/
MIT License
13.8k stars 3.2k forks source link

Database.SqlQuery ignores value conversion #35088

Closed amyboose closed 1 week ago

amyboose commented 1 week ago

File a bug

I have context models and a lot of primitive obsession inside. But when I try to use SqlQuery, it throws an exception. I need to join raw sql with my context models. Without primitive obsession it is not simple to make it works.

Include your code

#pragma warning disable IDE0059 

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;

namespace PrimitiveTypes;
public class Program
{
    public static async Task Main()
    {
        MyContext context = new();
        context.Database.EnsureDeleted();
        context.Database.EnsureCreated();

        List<UserModel> userModels = context.Database
            .SqlQuery<UserModel>($"select \"Id\", \"Age\" from \"Users\"")
            .ToList();
    }
}

public readonly record struct UserId
{
    public UserId(int value)
    {
        Value = value;
    }

    public int Value { get; }
}

public class UserIdConverter : ValueConverter<UserId, int>
{
    public UserIdConverter()
        : base(x => x.Value, x => new UserId(x))
    {
    }
}

public class User
{
    public UserId Id { get; set; }
    public string FullName { get; set; }
    public int Age { get; set; }
}

public class UserModel
{
    public UserId Id { get; set; }
    public int Age { get; set; }
}

public class MyContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder
            .UseNpgsql(@"Host=localhost;Port=5491;Database=testdb;Username=postgres;Password=adminpass")
            .LogTo(Console.WriteLine, LogLevel.Information)
            .EnableSensitiveDataLogging();
    }

    protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
    {
        configurationBuilder
            .Properties<UserId>()
            .HaveConversion<UserIdConverter>();
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>(builder =>
        {
        });
    }
}

Include stack traces

System.InvalidOperationException: "The property 'UserModel.Id' could not be mapped because it is of type 'UserId', which is not a supported primitive type or a valid entity type. The property can be ignored using the '[NotMapped]' attribute."

Include provider and version information

EF Core version: 8.0.10 EF tools version: 8.0.10 Database provider: Npgsql Target framework: .NET 8.0 Operating system: Windows 11 IDE: Visual Studio 2022 17.10.5

roji commented 1 week ago

Duplicate of #33206

roji commented 1 week ago

@amyboose ConfigureConventions currently affects only mapped types, and UserModel is mapped in your code. See #33206 for more discussion on this.