Search code examples
c#.net-coreentity-framework-coreef-core-7.0

EF Core 7.0 Error: "Add the entity seed to 'X' and specify the foreign key values" when already specified


I am having trouble seeding unidirectional relationships. The seeding looks as follows:

  • User 1-->* Post

I'm receive this error on configuration

Unhandled exception. System.InvalidOperationException: The seed entity for entity type 'User' with the key value 'Id:1' cannot be added because it has the navigation 'Posts' set. To seed relationships, add the entity seed to 'Post' and specify the foreign key values {'UserId'}.

This error makes no sense to me, as I am already explicitly specifying the foreign key value Post.UserId...

Any help is much appreciated!

Here is my configuration

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Models.User>()
        .HasMany(user => user.Posts)
        .WithOne()
        .HasForeignKey(post => post.UserId)
        .IsRequired(false);

    Models.User user = new() { Id = 1, Username = "user" };
    Models.Post post = new() { Id = 1, Body = "Hello from the other side", UserId = 1 };
    user.Posts.Add(post);

    modelBuilder.Entity<Models.User>().HasData(user);
    modelBuilder.Entity<Models.Post>().HasData(post);
}

And here are my class definitions

public abstract class Base
{
    [Key]
    public int Id { get; set; }
    public DateTime CreatedAt { get; set; } = DateTime.Now;
    public DateTime? UpdateAt { get; set; }
}

public class Post : Base
{
    [Required] public string Body { get; set; }
    public int? UserId { get; set; }
}

public class User : Base
{
    [Required] public string Username { get; set; }
    [ForeignKey(nameof(Post.UserId))] public ICollection<Post> Posts { get; set; } = new List<Post>();
}

Solution

  • I found the error in my implementation for anyone experiencing the same.

    In the creation phase, you are not supposed to populate virtual collections, in this case User.Posts, as the foreign key is what EF uses to populate the collections later on. Basicailly remove user.Posts.Add(post);

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Models.User>()
            .HasMany(user => user.Posts)
            .WithOne()
            .HasForeignKey(post => post.UserId)
            .IsRequired(false);
    
        Models.User user = new() { Id = 1, Username = "user" };
        Models.Post post = new() { Id = 1, Body = "Hello from the other side", UserId = 1 };
    
        modelBuilder.Entity<Models.User>().HasData(user);
        modelBuilder.Entity<Models.Post>().HasData(post);
    }
    

    On top of that, EF implements lazy loading behind the scenes, so when fetching data from the DB, you must include your virtual collections to populate them. This is in repositories/User.cs:

    public static Models.User? Get(string username)
    {
        using Contexts.Main context = new();
        return context.Users.Include(user => user.Posts).SingleOrDefault(user => user.Username == username);
    }