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

ef core migration add Error with using Strongy Type record as Identity #35068

Closed vicheanath closed 1 week ago

vicheanath commented 2 weeks ago

ef core migration add Error with using Strongy Type record as Identity

Problem

I have a problem with ef core migration strongly type id I have use conversion for convert it back to Guid on database mapper but it still treat UserId as an Entity and requires me to give key to it .

User.cs


public record UserId(Guid Value) : IEntityId;

public record Name(string FirstName, string LastName);

public class Email : ValueObject
{
    public string Value { get; }

    public Email(string value)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            throw new ArgumentException("The email cannot be null or empty.", nameof(value));
        }

        Value = value;
    }

    public static implicit operator string(Email email) => email.Value;

    protected override IEnumerable<object> GetAtomicValues()
    {
        yield return Value;
    }
}

public record Username(string Value);

public class User : Entity<UserId>, ISoftDeletable, IAuditable
{
    public UserId UserId { get; private set; }

    public Username Username { get; private set; }

    public Name Name { get; private set; }

    public Email Email { get; private set; }

    public string Password { get; private set; }

    public bool IsDeleted { get; private set; }

    public DateTime? DeletedOnUtc { get; private set; }

    public DateTime CreatedOnUtc { get; private set; }

    public DateTime? ModifiedOnUtc { get; private set; }
    public IReadOnlyCollection<Role> Roles => _roles.ToList().AsReadOnly();
    private readonly HashSet<Role> _roles = new();
}

UserConfigMapper.cs

private static void ConfigureDataStructure(EntityTypeBuilder<User> builder)
    {
        builder.ToTable(TableNames.Users);
        builder.HasKey(u => u.Id);
        builder.Property(u => u.Id)
            .ValueGeneratedNever()
            .HasConversion(id => id.Value, value => new UserId(value));
        builder.OwnsOne(u => u.Name, name =>
        {
            name.Property(n => n.FirstName)
                .HasMaxLength(100);
            name.Property(n => n.LastName)
                .HasMaxLength(100);
        });
        builder.OwnsOne(u => u.Email, email =>
        {
            email.Property(e => e.Value)
                .HasMaxLength(225);
        });
        builder.Property(u => u.Password)
            .HasMaxLength(200);
    }

Include verbose output

Please include --verbose output when filing bugs about the dotnet ef or Package Manager Console tools.

Use triple-tick fences for tool output. For example:

Build started...
Build succeeded.
Unable to create a 'DbContext' of type ''. The exception 'The entity type 'UserId' requires a primary key to be defined. If you intended to use a keyless entity type, call 'HasNoKey' in 'OnModelCreating'. For more information on keyless entity types, see https://go.microsoft.com/fwlink/?linkid=2141943.' was thrown while attempting to create an instance. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728

Include provider and version information

EF Core version: 8.0.10 Database provider: (e.g. Microsoft.EntityFrameworkCore.PostgreSQL) Target framework: .NET 8.0 Operating system: MAC IDE: VS Code

roji commented 1 week ago

You'll have to submit an minimal, runnable code repro - the above is a partial snippet that doesn't allow me to reproduce the problem. See below for an example code sample which maps your UserId property just fine.

Attempted repro ```c# await using var context = new BlogContext(); await context.Database.EnsureDeletedAsync(); await context.Database.EnsureCreatedAsync(); public class BlogContext : DbContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder .UseNpgsql("Host=localhost;Username=test;Password=test") .LogTo(Console.WriteLine, LogLevel.Information) .EnableSensitiveDataLogging(); protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity() .Property(u => u.UserId) .ValueGeneratedNever() .HasConversion(id => id.Value, value => new UserId(value)); } } public class User { public UserId UserId { get; private set; } } public record UserId(Guid Value) : IEntityId; public interface IEntityId {} ```
vicheanath commented 1 week ago

Thank for your reply actually that is my fail , i don't specify enough property filed, can close this issue