Home > Software engineering >  Seed owned type in EF Core 5
Seed owned type in EF Core 5

Time:01-02

I have the following configuration for which I want to provide some seed values.

 void IEntityTypeConfiguration<Beneficiary>.Configure(EntityTypeBuilder<Beneficiary> builder)
    {
        builder.HasKey(pk => pk.Id);

        builder.Property(pk => pk.Id)
            .UseIdentityColumn()
            .ValueGeneratedOnAdd();

        builder.HasData(
            new
            {
                Id = -1,
            });

        builder
            .OwnsOne(self => self.Invoice,
                nav =>
                {
                    nav.ToTable("Invoices");
                    nav.Property(nav => nav.Number).HasMaxLength(16).IsRequired();
                    nav.Property(nav => nav.IssueDate).HasDefaultValueSql("getutcdate()");
                })
            .HasData(new
            {
                BeneficiaryId = -1,
                Number = "000"
            });

        builder
            .Navigation(self => self.Invoice)
            .IsRequired();
    }

I've followed this example example-to-seed but I'm getting

The seed entity for entity type 'Beneficiary' cannot be added because > the value '-1' provided for the property 'Id' is not of type 'long'.

CodePudding user response:

This is very similar to How to fix EF Core migration error on join table configuration, but for owned entity type.

Be careful with fluent API overloads, as they return different things. For instance, OwnsOne without builder action delegate returns a builder for the owned entity type. But the overload with action returns the original (owner) entity builder so you can continue configuring it (the configuration of the owned entity is considered to be inside the action delegate).

In your case, here


.OwnsOne(self => self.Invoice,
    nav =>
    {
        nav.ToTable("Invoices");
        nav.Property(nav => nav.Number).HasMaxLength(16).IsRequired();
        nav.Property(nav => nav.IssueDate).HasDefaultValueSql("getutcdate()");
    }) // <-- problem
.HasData(new
{
    BeneficiaryId = -1,
    Number = "000"
});

you are exiting the owned entity builder scope (similar to the linked post join entity builder) and the next HasData is actually defining seed data for the Beneficiary rather than for intended Invoice. And since you are using anonymous type, C# is happily accepting it and you get that error at runtime.

To fix the issue, simply move the data seeding at the proper place, e.g.

.OwnsOne(self => self.Invoice,
    nav =>
    {
        nav.ToTable("Invoices");
        nav.Property(nav => nav.Number).HasMaxLength(16).IsRequired();
        nav.Property(nav => nav.IssueDate).HasDefaultValueSql("getutcdate()");
        // move here
        nav.HasData(new
        {
            BeneficiaryId = -1,
            Number = "000"
        });
    });
  • Related