借用微软EFCore8官方的示例,我画了张类图:

blog(博客)与Post(文章)是1对多的关系,显式表达出两者间是双向导航:双方都可见。

Post(文章)与Tag(标签)是多对多的关系,单向导航:Post可见Tag,但是Tag不可见Post。

映射到代码(注意,为了能够进行数据库迁移,手动改了一些地方,比如增加了Id,但是实体类是可用的):

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

*说明3:由于“Tag不可见Post”,所以不必设置导航属性。

注意以上代码:

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 information
            Console.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文库

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐