EF Core中如何设置数据库表自己与自己的多对多关系

本文的代码基于.NET Core 3.0和EF Core 3.0

有时候在数据库设计中,一个表自己会和自己是多对多关系。

在SQL Server数据库中,现在我们有Person表,代表一个人,建表语句如下:

CREATE TABLE [dbo].[Person](
    [PersonID] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](50) NULL,
    [Age] [int] NULL,
 CONSTRAINT [PK_Person] PRIMARY KEY CLUSTERED
(
    [PersonID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

其中PersonID列是Person表的主键。

因为一个人会有多个朋友,所以实际上这种人与人之间的朋友关系,是Person表自己和自己的多对多关系,所以我们还要建立一张FriendRelation表,来表示Person表自身的多对多关系,FriendRelation表的建表语句如下:

CREATE TABLE [dbo].[FriendRelation](
    [FriendRelationID] [int] IDENTITY(1,1) NOT NULL,
    [FromPerson] [int] NULL,
    [ToPerson] [int] NULL,
    [Remark] [nvarchar](100) NULL,
 CONSTRAINT [PK_FriendRelation] PRIMARY KEY CLUSTERED
(
    [FriendRelationID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[FriendRelation]  WITH CHECK ADD  CONSTRAINT [FK_FriendRelation_Person_From] FOREIGN KEY([FromPerson])
REFERENCES [dbo].[Person] ([PersonID])
GO

ALTER TABLE [dbo].[FriendRelation] CHECK CONSTRAINT [FK_FriendRelation_Person_From]
GO

ALTER TABLE [dbo].[FriendRelation]  WITH CHECK ADD  CONSTRAINT [FK_FriendRelation_Person_To] FOREIGN KEY([ToPerson])
REFERENCES [dbo].[Person] ([PersonID])
GO

ALTER TABLE [dbo].[FriendRelation] CHECK CONSTRAINT [FK_FriendRelation_Person_To]
GO

其中FriendRelationID列是FriendRelation表的主键,我们可以看到在FriendRelation表中有两个外键关系:

  • 外键关系[FK_FriendRelation_Person_From],通过FriendRelation表的外键列[FromPerson],关联到Person表的主键列PersonID
  • 外键关系[FK_FriendRelation_Person_To],通过FriendRelation表的外键列[ToPerson],关联到Person表的主键列PersonID

因此Person表每行数据之间的多对多关系,就通过FriendRelation表的[FromPerson]列和[ToPerson]列建立起来了。

接下来,我们使用EF Core的DB First模式,通过Scaffold-DbContext指令,来生成实体类和DbContext类。

生成Person实体类如下:

using System;
using System.Collections.Generic;

namespace EFCoreSelfMany.Entities
{
    public partial class Person
    {
        public Person()
        {
            FriendRelationFromPersonNavigation = new HashSet<FriendRelation>();
            FriendRelationToPersonNavigation = new HashSet<FriendRelation>();
        }

        public int PersonId { get; set; }
        public string Name { get; set; }
        public int? Age { get; set; }

        public virtual ICollection<FriendRelation> FriendRelationFromPersonNavigation { get; set; }
        public virtual ICollection<FriendRelation> FriendRelationToPersonNavigation { get; set; }
    }
}

可以看到EF Core在实体类Person中生成了两个属性:

  • FriendRelationFromPersonNavigation属性,对应了FriendRelation表的外键列[FromPerson]
  • FriendRelationToPersonNavigation属性,对应了FriendRelation表的外键列[ToPerson]

所以通过这两个属性我们就能知道一个人有哪些朋友。

生成FriendRelation实体类如下:

using System;
using System.Collections.Generic;

namespace EFCoreSelfMany.Entities
{
    public partial class FriendRelation
    {
        public int FriendRelationId { get; set; }
        public int? FromPerson { get; set; }
        public int? ToPerson { get; set; }
        public string Remark { get; set; }

        public virtual Person FromPersonNavigation { get; set; }
        public virtual Person ToPersonNavigation { get; set; }
    }
}

可以看到EF Core在实体类FriendRelation中也生成了两个属性:

  • FromPersonNavigation属性,对应了FriendRelation表的外键列[FromPerson]
  • ToPersonNavigation属性,对应了FriendRelation表的外键列[ToPerson]

所以通过这两个属性,我们可以知道一个朋友关系中的两个人(Person表)到底是谁。

最后我们来看看,生成的DbContext类DemoDBContext:

using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;

namespace EFCoreSelfMany.Entities
{
    public partial class DemoDBContext : DbContext
    {
        public DemoDBContext()
        {
        }

        public DemoDBContext(DbContextOptions<DemoDBContext> options)
            : base(options)
        {
        }

        public virtual DbSet<FriendRelation> FriendRelation { get; set; }
        public virtual DbSet<Person> Person { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {
                optionsBuilder.UseSqlServer("Server=localhost;User Id=sa;Password=Dtt!123456;Database=DemoDB");

                optionsBuilder.UseLoggerFactory(new EFLoggerFactory());
            }
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<FriendRelation>(entity =>
            {
                entity.Property(e => e.FriendRelationId).HasColumnName("FriendRelationID");

                entity.Property(e => e.Remark).HasMaxLength(100);

                entity.HasOne(d => d.FromPersonNavigation)
                    .WithMany(p => p.FriendRelationFromPersonNavigation)
                    .HasForeignKey(d => d.FromPerson)
                    .HasConstraintName("FK_FriendRelation_Person_From");

                entity.HasOne(d => d.ToPersonNavigation)
                    .WithMany(p => p.FriendRelationToPersonNavigation)
                    .HasForeignKey(d => d.ToPerson)
                    .HasConstraintName("FK_FriendRelation_Person_To");
            });

            modelBuilder.Entity<Person>(entity =>
            {
                entity.Property(e => e.PersonId).HasColumnName("PersonID");

                entity.Property(e => e.Name).HasMaxLength(50);
            });

            OnModelCreatingPartial(modelBuilder);
        }

        partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
    }
}

可以看到在实体类FriendRelation的Fluent API中(黄色高亮部分),设置了Person实体类自己与自己的多对多关系。

然后我们在.NET Core控制台项目中,写了几个方法来做测试:

原文地址:https://www.cnblogs.com/OpenCoder/p/11806945.html

时间: 2024-10-09 11:52:55

EF Core中如何设置数据库表自己与自己的多对多关系的相关文章

EF Core 中DbContext不会跟踪聚合方法和Join方法返回的结果

EF Core中: 如果调用Queryable.Count等聚合方法,不会导致DbContext跟踪(track)任何实体. 此外调用Queryable.Join方法返回的匿名类型也不会被DbContext所跟踪(实测调用Queryable.Join方法返回EF Core中的实体类型也不会被DbContext所跟踪). Queryable.Count等聚合方法和Queryable.Join方法返回的结果不会被跟踪,原因是因为这两种方法返回的结果类型并没有被DbContext的OnModelCre

EF Core中执行Sql语句查询操作之FromSql,ExecuteSqlCommand,SqlQuery

一.目前EF Core的版本为V2.1 相比较EF Core v1.0 目前已经增加了不少功能. EF Core除了常用的增删改模型操作,Sql语句在不少项目中是不能避免的. 在EF Core中上下文,可以返货DbConnection ,执行sql语句.这是最底层的操作方式,代码写起来还是挺多的. 初次之外 EF Core中还支持 FromSql,ExecuteSqlCommand 连个方法,用于更方便的执行Sql语句. 另外,目前版本的EF Core 不支持SqlQuery,但是我们可以自己扩

数据库一对一、一对多、多对多关系

数据库一对一.一对多.多对多关系 一.首先给出三种关系的实例 一对一关系实例 ? 一个人对应一张身份证,一张身份证对应一个人 一对多关系实例 ? 一个公司的部门拥有多个职员,一个职员只能够属于某个部门 多对多实例 ? 一本图示可以拥有多个作者,一个作者可以写很多本书. 一对一关系 一对多,是最常见的一种设计.就是 A 表的一条记录,对应 B 表的多条记录,且 A 的主键作为 B 表的外键.这主要看以哪张表为中心. 优点 便于管理.可提高一定的查询速度 减轻 CPU 的 IO 读写,提高存取效率.

ef core中如何实现多对多的表映射关系

文档:https://docs.microsoft.com/en-us/ef/core/modeling/relationships class MyContext : DbContext { public DbSet<Post> Posts { get; set; } public DbSet<Tag> Tags { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { m

EF Core中的DB First与Code First

前言: 大家都习惯在程序中生成对应的model来对数据库进行操作,所以如何快速的生成数据库表的对应model,是基础之一.总结了一下在我的认知中大概是这个结构: Db first方式: 先创建好对应的数据库通过数据库来生成对应的Model. 1 创建数据库 大家可根据自己的需要生成对应的数据库,这里只做演示所以使用官方给的SqlServer数据库脚本: CREATE DATABASE [Blogging]; GO USE [Blogging]; GO CREATE TABLE [Blog] (

EF Core 中实现 动态数据过滤器

前言 在项目开发中,我们很多时候都会设计  软删除.所属用户 等等一系列字段 来方便我们在业务查询的时候进行各种过滤 然后引申的问题就是: 在业务查询的时候,我们要如何加上这些条件?或者动态禁用某些查询条件呢? EF Core自带的全局过滤查询功能 EF Core提供了一个HasQueryFilter 供我们在查询的时候进行预置部分筛选条件 例如:     builder.HasQueryFilter(x => !x.IsDelete); 这样查询的时候  EF Core 会自动帮我们实现过滤

实验:模拟场景中误删除mysql数据库表,然后使用全备份以及二进制日志文件恢复操作

一.实验环境: 1.准备两台虚拟机,一台用于破坏数据库,一台用于还原,两台在同一个网络 2.两台最小化安装centos 7系统,并直接yum安装maraidb数据库 3.准备一个测试数据库文件,例如,hellodb_innodb.mysql 测试库里面最少有两个表. 二.实验步骤: 1.开启数据库的二进制日志功能 vim /etc/my.cnf[mysqld] 下面加入log-bin 表示开启二进制日志功能 2.完全备份 mysqldump -A -F --master-data=2 --sin

EF Core中DeleteBehavior的介绍(转自MSDN)

Delete behaviors Delete behaviors are defined in the DeleteBehavior enumerator type and can be passed to the OnDelete fluent API to control whether the deletion of a principal/parent entity or the severing of the relationship to dependent/child entit

数据库一对一,一对多,多对多关系

关联映射:一对多/多对一 存在最普遍的映射关系,简单来讲就如球员与球队的关系: 一对多:从球队角度来说一个球队拥有多个球员 即为一对多 多对一:从球员角度来说多个球员属于一个球队 即为多对一 数据表间一对多关系如下图: 关联映射:一对一 一对一关系就如球队与球队所在地址之间的关系,一支球队仅有一个地址,而一个地址区也仅有一支球队. 数据表间一对一关系的表现有两种,一种是外键关联,一种是主键关联.图示如下: 一对一外键关联: 一对一主键关联:要求两个表的主键必须完全一致,通过两个表的主键建立关联关