Q:

How to make one-to-many relationship between 3 entities work with Entity Framework Core 2.1 - code-first

I have 3 entities mapped to each other with one-to-many relationship, one of them should be mapped to both of them which is resulting in unwanted many-to-many relationship.  
  Here is the logic behind the mapping: 

User can have many Posts; Post has only one user.  
User can have many Categories; Category has only one user. 
Category can have many posts; Post has only one category.  

Here is my code:
User
Table("Users")]
Public Class User
{
        [Key]
        public int UserId { get; set; }
        [Required]
        public string FirstName { get; set; }
        [Required]
        public string LastName { get; set; }
        [Required]
        public string UserName { get; set; }
        public DateTime CreatedAt { get; set; }

        public ICollection<Posts> Posts { get; set; }
        public ICollection<Category> Categories { get; set; }
}

 Post
[Table("Posts")]
    public class Post
    {
        [Key]
        public int PostId { get; set; }
        [Required]
        public string Title { get; set; }
        [Required]
        public string Description { get; set; }
        [Required]
        public string Text { get; set; }
        public DateTime CreatedAt { get; set; }
        public DateTime?  UpdatedAt { get; set; }

        public int UserId { get; set; }
        public User User { get; set; }

        public int CategoryId { get; set; }
        public Category Category { get; set; }

    }

 Category
 [Table("Categories")]
    public class Category
    {
        [Key]
        public int CategoryId { get; set; }
        [Required]
        public string Name { get; set; }
        [Required]
        public string Description { get; set; }
        public DateTime CreatedAt { get; set; }

        public int UserId { get; set; }
        public User User { get; set; }

        public ICollection<Post> Posts { get; set; }
    }

 My Db Context 
 public class BlogContext : DbContext
    {

        public DbSet<User> Users { get; set; }
        public DbSet<Post> Posts{ get; set; }
        public DbSet<Category> Categories { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {

            modelBuilder. Entity<User>(entity =>
            {
                entity. HasMany<Post>(s => s.Posts)
                .WithOne(u => u.User)
                .HasForeignKey(s => s.UserId)
                .OnDelete(DeleteBehavior. Restrict);

                entity. HasMany<Category>(c => c.Categories)
                .WithOne(u => u.User)
                .HasForeignKey(c => c.UserId)
                .OnDelete(DeleteBehavior. Restrict);

                entity. Property(u => u.CreatedAt)
                .HasDefaultValueSql("SYSUTCDATETIME()");
            });

            modelBuilder. Entity<Post>(entity =>
            {

                entity. HasOne<Category>(s => s.Category)
                .WithMany(c => c.Posts)
                .HasForeignKey(s => s.PostId);

                entity. HasOne<User>(s => s.User)
                .WithMany(u => u.Posts)
                .HasForeignKey(s => s.PostId);

                entity. Property(s => s.CreatedAt)
                .HasDefaultValueSql("SYSUTCDATETIME()");
            });

            modelBuilder. Entity<Category>(entity =>
            {
                entity. HasMany<Post>(c => c.Posts)
                .WithOne(s => s.Category)
                .HasForeignKey(c => c.PostId)
                .OnDelete(DeleteBehavior. Restrict);

                entity. Property(c => c.CreatedAt)
                .HasDefaultValueSql("SYSUTCDATETIME()");
            });

        }
    }

I ran into this problem when inserting posts: 
The property 'PostId' on entity type 'Post' has a temporary value

What I understood is that I caused many-to-many relationship with the way that I've implemented the DbContext.  How can I fix it?  Thanks for helping. 

A:

You didn't configure the foreign key correctly.  Let's review your code of Entity<Post>(entity=>{ /* ... */ }):

modelBuilder. Entity<Post>(entity =>
{
    entity. HasOne<Category>(s => s.Category)
        .WithMany(c => c.Posts)
        .HasForeignKey(s => s.PostId);  // line A: it is not correct! 

    entity. HasOne<User>(s => s.User)
        .WithMany(u => u.Posts)
        .HasForeignKey(s => s.PostId); // line B: it is not correct! 

    entity. Property(s => s.CreatedAt)
        .HasDefaultValueSql("SYSUTCDATETIME()");
});

Note the line A and line B are not correct.  As in both cases, the dependent entity is Post.  Your code will result in a foreign key as below:
CREATE TABLE [Posts] (
    [PostId] int NOT NULL,
    [Title] nvarchar(max) NOT NULL,
    [Description] nvarchar(max) NOT NULL,
    [Text] nvarchar(max) NOT NULL,
    [CreatedAt] datetime2 NOT NULL DEFAULT (SYSUTCDATETIME()),
    [UpdatedAt] datetime2 NULL,
    [UserId] int NOT NULL,
    [CategoryId] int NOT NULL,
    CONSTRAINT [PK_Posts] PRIMARY KEY ([PostId]),
    CONSTRAINT [FK_Posts_Categories_PostId] FOREIGN KEY ([PostId]) REFERENCES [Categories] ([CategoryId]) ON DELETE NO ACTION,
    CONSTRAINT [FK_Posts_Users_PostId] FOREIGN KEY ([PostId]) REFERENCES [Users] ([UserId]) ON DELETE NO ACTION
);

So you need change your code as below:
modelBuilder. Entity<Post>(entity =>
{
    entity. HasOne<Category>(s => s.Category)
        .WithMany(c => c.Posts)
        //.HasForeignKey(s => s.PostId);
        .HasForeignKey(s => s.CategoryId);

    entity. HasOne<User>(s => s.User)
        .WithMany(u => u.Posts)
        //.HasForeignKey(s => s.PostId);
        .HasForeignKey(s => s.UserId);

    entity. Property(s => s.CreatedAt)
        .HasDefaultValueSql("SYSUTCDATETIME()");
});

Because of the same reason, you should also change the part of Entity<Category>(entity=>{ /* ... */ }) as below:
modelBuilder. Entity<Category>(entity =>
{
    entity. HasMany<Post>(c => c.Posts)
        .WithOne(s => s.Category)
        //.HasForeignKey(c => c.PostId)     // remove this line
        .HasForeignKey(c => c.CategoryId)   // add this line
        .OnDelete(DeleteBehavior. Restrict);

    entity. Property(c => c.CreatedAt)
        .HasDefaultValueSql("SYSUTCDATETIME()");
});

