Search code examples
entity-framework-coreentity-framework-core-2.2

How to Seed self referencing tree using Entity Framework Core 2.2


When I try to add migration there is the following exception:

The seed entity for entity type 'Genre' cannot be added because it has the navigation 'SubGenres' set. To seed relationships, you need to add the related entity seed to 'Genre' and specify the foreign key values {'ParentId'}

How I can properly setup seed in EntityFrameworkCore 2.2

I have the next entity

public class Genre
{
    [Key] public int Id { get; set; }

    [Required] [MaxLength(50)] public string Name { get; set; }

    public virtual ICollection<GameGenre> GameGenre { get; set; } = new List<GameGenre>();
    public int? ParentId { get; set; }
    public virtual Genre ParentGenre { get; set; }
    public virtual ICollection<Genre> SubGenres { get; set; } = new List<Genre>();
}

DbContext

public class OnlineGameContext : DbContext
{
    public OnlineGameContext(DbContextOptions<OnlineGameContext> options)
        : base(options)
    {
    }

    public DbSet<Genre> Genres { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder
            .Entity<Genre>()
            .HasMany(u => u.SubGenres)
            .WithOne(p => p.ParentGenre)
            .HasForeignKey(p => p.ParentId);

       modelBuilder.Entity<Genre>().HasData(DefaultGenresFactories.Action);
       base.OnModelCreating(modelBuilder);

    }

}

Factories

public static class DefaultGenresFactories
{
    public static Genre Action =>
        new Genre
        {
            Id = 5,
            Name = "Action",
            SubGenres = DefaultSubGenresFactories.Action
        };

}



public static class DefaultSubGenresFactories
 {
        public static ICollection<Genre> Action => new List<Genre>
        {
            new Genre
            {
                Id = 15,
                Name = "FPS",
                ParentId = 5
            },
            new Genre
            {
                Id = 16,
                Name = "TPS",
                ParentId = 5
            },
            new Genre
            {
                Id = 17,
                Name = "Misc",
                ParentId = 5
            }
        };
}

Solution

  • The exception message is telling you that you cannot use navigation properties when seeding with HasData method, but instead you could specify the relationships only via FK properties.

    In other words, you can't use SubGenres and ParentGenre navigation properties for specifying the relations, they can be specified only via ParentId property.

    So remove the

    SubGenres = DefaultSubGenresFactories.Action
    

    line, and either consolidate the DefaultSubGenresFactories.Action and DefaultGenresFactories.Action to a single list of Genre and use that list in HasData call, or if you want to keep the DefaultGenresFactories and DefaultSubGenresFactories classes separate as they are currently, simply call HasData for both (it's additive):

    modelBuilder.Entity<Genre>().HasData(DefaultGenresFactories.Action);
    modelBuilder.Entity<Genre>().HasData(DefaultSubGenresFactories.Action);