EF Core DDD many-to-one relationship, foreign key is always null

Viewed 228

Relation: many products can belong to the same category. Have simplified the domain models to focus on the issue.

I'm using EF Core v5.0.

Product model class:

public class Product: Entity, IAggregateRoot
{
    protected Product() { }

    public Product(string name, Category category): this()
    {
        Name = name;
        Category = category;
    }

    public string Name { get; }
    public virtual Category Category { get; }
}

Category model class:

public class Category: Entity
{
    protected Category() { }

    public Category(string name): this()
    {
        Name = name;
    }

    public string Name { get; }
}

Product configuration:

public class ProductConfiguration: IEntityTypeConfiguration<Product>
{
    public void Configure(EntityTypeBuilder<Product> builder)
    {
        builder.ToTable("Product");

        builder.HasKey(x => x.Id);

        builder.Property(x => x.Id)
               .HasValueGenerator<StringValueGenerator>()
               .ValueGeneratedOnAdd();

        builder.Property(x => x.Name).IsRequired().HasMaxLength(500);
        
        builder.HasOne<Category>().WithMany();
    }

    #endregion
}

Category configuration:

public class CategoryConfiguration: IEntityTypeConfiguration<Category>
{
    public void Configure(EntityTypeBuilder<Category> builder)
    {
        builder.ToTable("Category");

        builder.HasKey(x => x.Id);

        builder.Property(x => x.Id)
               .HasValueGenerator<StringValueGenerator>()
               .ValueGeneratedOnAdd();

        builder.Property(x => x.Name)
               .IsRequired()
               .HasMaxLength(255);
    }

    #endregion
}

So having this configuration and domain models in place, when trying to insert some seed data the CategoryId property (shadow property created by EF Core, and not in the domain model) is always null.

public class ProductDbContextSeeder
{
    public async Task SeedAsync(ProductDbContext context)
    {
        var category = await context.Categories.FirstOrDefaultAsync(x => x.Name == "Test Category");

        if (category is null)
        {
            category = new Category("Test Category");
            await context.Categories.AddAsync(category);
            await context.SaveChangesAsync();
        }

        var product = await context.Products.FirstOrDefaultAsync(x => x.Name == "Test Product");

        if (product is null)
        {
            product = new Product("Test Product", category);
            context.Products.Attach(product);
            await context.SaveChangesAsync();
        }
    }
}

I have inspected the state of the entries right before the call to context.SaveChangesAsync() and it seems that the entities are in correct state as below:

When saving Category:

  • Category -> Added

When saving Product:

  • Product -> Added
  • Category -> Unchanged

What am I missing? Appreciate any hints, pointers.

Thanks

0 Answers
Related