.NET 雲原生架構師訓練營(模組二 基礎鞏固 EF Core 關係)--學習筆記

MingsonZheng發表於2020-12-29

2.4.4 EF Core -- 關係

  • 一對多
  • 一對一
  • 多對多
  • 示例

關係:https://docs.microsoft.com/zh-cn/ef/core/modeling/relationships?tabs=fluent-api%2Cfluent-api-simple-key%2Csimple-key

一對多

// Dependent Entity 主表
public class Blog
{
    // Principal Key 標識鍵/可能是主鍵或者備用鍵(唯一性約束)
    public int BlogId { get; set; }
    
    public string Url { get; set; }

    // Collection navigation property 關聯多個從表的屬性集合(集合屬性)
    public List<Post> Posts { get; set; }
}

// Principal Entity 從表
public class Post
{
    public int PostId { get; set; }
    
    public string Title { get; set; }
    
    public string Content { get; set; }

    // Foreign Key 外來鍵(指向主表中的 Principal Key)
    // Inverse navigation property 反向導航屬性
    public int BlogId { get; set; }

    // Inverse navigation property 反向導航屬性
    public Blog Blog { get; set; }
}

一對一

// Principal Entity 從表
public class Blog
{
    public int BlogId { get; set; }
    
    public string Url { get; set; }

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

// Dependent Entity 主表
public class Post
{
    public int PostId { get; set; }
    
    public string Title { get; set; }
    
    public string Content { get; set; }

    // Reference navigation property 一對一時指向另外一張表(引用屬性)
    public Blog Blog { get; set; }
}

多對多

public class Post
{
    public int PostId { get; set; }
    
    public string Title { get; set; }
    
    public string Content { get; set; }

    public ICollection<Tag> Tags { get; set; }
}

public class Tag
{
    public string TagId { get; set; }

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

示例

一對多

一個 Project 對應多個 ProjectGroup

在 Project 實體中新增 ProjectGroup 列表

public List<ProjectGroup> Groups { get; set; }

遷移

dotnet ef migrations add ProjectGroupCollectionProperty

生成集合屬性 ProjectGroupCollectionProperty

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.AlterColumn<string>(
        name: "ProjectId",
        table: "ProjectGroups",
        nullable: true,
        oldClrType: typeof(string),
        oldType: "longtext CHARACTER SET utf8mb4",
        oldNullable: true);

    migrationBuilder.CreateIndex(
        name: "IX_ProjectGroups_ProjectId",
        table: "ProjectGroups",
        column: "ProjectId");

    migrationBuilder.AddForeignKey(
        name: "FK_ProjectGroups_Projects_ProjectId",
        table: "ProjectGroups",
        column: "ProjectId",
        principalTable: "Projects",
        principalColumn: "Id",
        onDelete: ReferentialAction.Restrict);
}

手動配置

class MyContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // 先在從表上建立一對一的關係,再從主表上建立一對多的關係
        modelBuilder.Entity<Post>()
            .HasOne(p => p.Blog)
            .WithMany(b => b.Posts);
    }
}

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

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

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public Blog Blog { get; set; }
}

LighterDbContext

// 一對一
modelBuilder.Entity<Project.ProjectGroup>().HasOne<Project.Project>(g => g.Project);
// 一對多
modelBuilder.Entity<Project.ProjectGroup>().HasOne<Project.Project>(g => g.Project).WithMany(p => p.Groups);

多對多

為 Project 和 Subject 建立中間表 SubjectProject

public class Project : Entity
{
    public string Title { get; set; }

    public DateTime StartDate { get; set; }

    public DateTime EndDate { get; set; }

    public string SupervisorId { get; set; }

    public string PlanId { get; set; }

    public List<ProjectGroup> Groups { get; set; }
    
    public List<SubjectProject> SubjectProjects { get; set; }
}

public class Subject : Entity
{
    public string Title { get; set; }

    public string Content { get; set; }
    
    public List<SubjectProject> SubjectProjects { get; set; }
}

public class SubjectProject : Entity
{
    public string ProjcetId { get; set; }

    public Project Project { get; set; }

    public string SubjectId { get; set; }

    public Subject Subject { get; set; }
}

配置多對多關係

LighterDbContext

// 多對多(兩組一對多)
modelBuilder.Entity<Project.SubjectProject>()
    .HasOne<Project.Project>(s => s.Project)
    .WithMany(p => p.SubjectProjects)
    .HasForeignKey(s => s.ProjcetId);
    
modelBuilder.Entity<Project.SubjectProject>()
    .HasOne<Project.Subject>(s => s.Subject)
    .WithMany(p => p.SubjectProjects)
    .HasForeignKey(s => s.SubjectId);

遷移

dotnet ef migrations add SubjectProjectManyToManyRelation

SubjectProjectManyToManyRelation

table.ForeignKey(
    name: "FK_SubjectProject_Projects_ProjcetId",
    column: x => x.ProjcetId,
    principalTable: "Projects",
    principalColumn: "Id",
    onDelete: ReferentialAction.Restrict);
table.ForeignKey(
    name: "FK_SubjectProject_Subject_SubjectId",
    column: x => x.SubjectId,
    principalTable: "Subject",
    principalColumn: "Id",
    onDelete: ReferentialAction.Restrict);

中間表建立了兩個外來鍵,形成多對多

EF Core 5.0 多對多實現

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public ICollection<Tag> Tags { get; set; }
}

public class Tag
{
    public string TagId { get; set; }

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

遷移的時候會自動生成中間表

聯接實體型別配置 HasMany

modelBuilder
    .Entity<Post>()
    .HasMany(p => p.Tags)
    .WithMany(p => p.Posts)
    .UsingEntity(j => j.ToTable("PostTags"));

GitHub原始碼連結:

https://github.com/MINGSON666/Personal-Learning-Library/tree/main/ArchitectTrainingCamp/LighterApi

相關文章