借用微软EFCore8官方的示例,我画了张类图:
blog(博客)与Post(文章)是1对多的关系,显式表达出两者间是双向导航:双方都可见。
Post(文章)与Tag(标签)是多对多的关系,单向导航:Post可见Tag,但是Tag不可见Post。
映射到代码(注意,手动改了一些地方,但是实体类是可用的):
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore;namespace MaxTools.EFCoreTest
{public class Blog{[Key]public int Id { get; set; }public string Name { get; set; }public string Owner { get; set; }public List<Post> Posts { get; set; }}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore;namespace MaxTools.EFCoreTest
{public class Post{[Key]public int Id { get; set; }public string Title { get; set; }public List<Tag> Tags { get; set; }[DeleteBehavior(DeleteBehavior.Cascade)]public Blog Blog { get; set; }}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.ComponentModel.DataAnnotations;namespace MaxTools.EFCoreTest
{public class Tag{[Key]public int Id { get; set; }public string Name { get; set; }}
}
注意以上代码:
1)双向导航中,双方都有导航属性List<...> ...
2)单向导航中,只有一方有属性List<...> ...
另外,需要考虑“组合关系”的时候,手动在代码里加映射属性,如下:
PostgresContext
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;namespace MaxTools.EFCoreTest;public partial class PostgresContext : DbContext
{public PostgresContext(){}public PostgresContext(DbContextOptions<PostgresContext> options): base(options){}protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see https://go.microsoft.com/fwlink/?LinkId=723263.=> optionsBuilder.UseNpgsql("PORT=5432;DATABASE=postgres;HOST=localhost;PASSWORD=postgres;USER ID=postgres;");protected override void OnModelCreating(ModelBuilder modelBuilder){OnModelCreatingPartial(modelBuilder);}partial void OnModelCreatingPartial(ModelBuilder modelBuilder);// DbSet 属性表示数据库中的表public DbSet<Blog> BlogSet { get; set; }public DbSet<Post> PostSet { get; set; }public DbSet<Tag> TagSet { get; set; }
}
客户端程序
using System;
using Microsoft.EntityFrameworkCore;namespace MaxTools.EFCoreTest
{public class Program{static void Main(){// See https://aka.ms/new-console-template for more informationConsole.WriteLine("Hello, World!");// Tag tag1 = new Tag();// tag1.Name = "testTag1";// Tag tag2 = new Tag();// tag2.Name = "testTag2";// List<Tag> tags1 = new List<Tag>();// tags1.Add(tag1);// tags1.Add(tag2);// Tag tag3 = new Tag();// tag3.Name = "testTag3";// Tag tag4 = new Tag();// tag4.Name = "testTag4";// List<Tag> tags2 = new List<Tag>();// tags2.Add(tag3);// tags2.Add(tag4);// Post post1 = new Post();// post1.Title = "post1";// post1.tags = tags1;// Post post2 = new Post();// post2.Title = "post2";// post2.tags = tags2;// List<Post> posts = new List<Post>();// posts.Add(post1);// posts.Add(post2);// Blog blog = new Blog();// blog.Name = "testBlog";// blog.Owner = "Zhang";// blog.Posts = posts;// PostgresContext context = new PostgresContext();// context.BlogSet.Add(blog);// int count = context.SaveChanges();// Console.WriteLine(count);// //删除PostgresContext context = new PostgresContext();Blog blog = context.BlogSet.Include(x => x.Posts).ThenInclude(x => x.Tags).FirstOrDefault(x => x.Id == 1);context.Remove(blog);int count = context.SaveChanges();Console.WriteLine(count);}}
}
在数据库中的表现为:
把逻辑的思考与数据库设计分离开。
以上代码经测可以级联删除,数据库是Postgres 16.1。
附件:【免费】blog中的示例代码,EFCore8+Postgres实现,调试通过资源-CSDN文库