如何使 3 个实体之间的一对多关系与 Entity Framework Core 2.1 一起工作 - 代码优先

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

我有 3 个实体通过一对多关系相互映射,其中一个应该映射到它们两个,这导致了不需要的多对多关系。

映射背后的逻辑如下:

这是我的代码:
用户

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; }

    }


类别

 [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; }
    }


我的数据库上下文

 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()");
            });

        }
    }

我运行插入帖子时遇到这个问题:

The property 'PostId' on entity type 'Post' has a temporary value

我的理解是,我用实现 DbContext 的方式造成了多对多关系。我该如何解决?感谢您的帮助。

你在

中犯了一个错误
    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()");
        });

Table类别模型没有PostId,User模型也没有。纠正这个。

您没有正确配置外键。让我们回顾一下您的代码 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()");
});

请注意,A 行和 B 行不正确。在这两种情况下,依赖实体都是 Post。您的代码将产生如下外键:

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
);

因此您需要如下更改代码:

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()");
});

因为同样的原因,你也应该把Entity<Category>(entity=>{ /* ... */ })的部分改成如下:

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()");
});