如何使 3 个实体之间的一对多关系与实体框架核心 2.1 一起使用 - 代码优先



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


发布

[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 的方式产生了多对多关系。我该如何解决它?感谢您的帮助。

您没有正确配置外键。让我们回顾一下您的Entity<Post>(entity=>{ /* ... */ })代码:

modelBuilder.Entity(entity =>{    实体。HasOne(s => s.Category(        .WithMany(c => c.Posts(        .HasForeignKey(s => s.PostId(; A行:不正确!    实体。HasOne(s => s.User(        .WithMany(u => u.Posts(        .HasForeignKey(s => s.PostId(;B行:不正确!    实体。属性(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()");
});

你在

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

表类别模型没有 PostId,用户模型也没有。更正此问题。

最新更新