EF Core 关系配置以及反向工程

每日英语:

//I‘m into sports//我喜欢运动  be into sth 
I can't believe you're watching that.
    The Golf Channel? I'm into golf. //Channel频道 ; 渠道 ; 电视台 ;
Since when?
    Since college.I used to play every day.

每日诗词:随机看一篇 没有目的性

五言绝句
行宫
唐代:元稹
寥落古行宫,宫花寂寞红。
白头宫女在,闲坐说玄宗。
译文
曾经富丽堂皇的古行宫已是一片荒凉冷落,宫中艳丽的花儿在寂寞寥落中开放。
幸存的几个满头白发的宫女,闲坐无事只能谈论着玄宗轶事。
注释
寥(liáo)落:寂寞冷落。行宫:皇帝在京城之外的宫殿。这里指当时东都洛阳
的皇帝行宫上阳宫。
宫花:行宫里的花。
白头宫女:据白居易《上阳白发人》,一些宫女天宝末年被“潜配”到上阳宫,
在这冷宫里一闭四十多年,成了白发宫人。
说:谈论。玄宗:指唐玄宗。
EF Core (反向工程)
// Scaffold [ˈskæfəʊld] 脚手架
Scaffold-DbContext ‘Server=.;'Database=demo1;Trusted_Connection=True'
    Microsoft.EntityFrameworkCore.SqlServer
    
作者推荐都是用Code First 但是由于项目有些是已经存在一部分数据库了  先做反向工程生成对应的实体类然后再自己添加或者修改实体类 最终其实还是Code First 模型驱动
每次反向工程都会覆盖之前的文件,(之前修改的代码还会丢失)
T_Cat 数据库中  生成的实体类为TCat  可能我们是需要修改生成的代码的;

总结:如果存在这种项目 第一次整理好数据库之后,进行对应的反向工程之后,对生成的实体类进行维护修改(增加FluentApi 或者Data Annotation),然后后续的操作全部基于Code First流程来。

查看EF Core 对实体类操作生成的对应的sql语句

EF Core 5.0以后不用自己引入日志来打印了 ,EF Core自带日志输出

在对应的XXXXDbContext里面的OnConfiguring方法添加LogTo即可

 protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        string connStr = "Server=.;Database=demo1;Trusted_Connection=True";
        optionsBuilder.UseSqlServer(connStr);
        optionsBuilder.LogTo(Console.WriteLine);
    }

由于EF Core底层帮我们屏蔽了不同数据库的差异,我们对于不同的数据库的操作代码是一样的,所以生成的sql脚本是不可以直接作用其他数据库的。

Add-Migration -OutputDir //使用这个命令会生成各个不同的数据库的迁移脚本

参考地址:https://docs.microsoft.com/zh-cn/ef/core/managing-schemas/migrations/providers?tabs=dotnet-core-cli

关系配置:

一对多,多对多,一对一

配置模式如下
//A有xxx个B对象,B对象中有YYY个A (xxx,yyy的可选择的数量是One或者Many)
HasXXX().WithYYY();
Delivery实体类以及DeliveryConfig
一对一
class Delivery
{
	public long Id { get; set; }
	public string CompanyName { get; set; }//快递公司名
	public String Number { get; set; }//快递单号
	public Order Order { get; set; }//订单
	public long OrderId { get; set; }//指向订单的外键
}

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

class DeliveryConfig : IEntityTypeConfiguration<Delivery>
{
	public void Configure(EntityTypeBuilder<Delivery> builder)
	{
		builder.ToTable("T_Deliveries");
		builder.Property(d => d.CompanyName).IsUnicode().HasMaxLength(10);
		builder.Property(d => d.Number).HasMaxLength(50);
	}
}
Order以及OrderConfig
class Order
{
	public long Id { get; set; }
	public string Name { get; set; }//商品名
	public string Address { get; set; }//收货地址
	public Delivery? Delivery { get; set; }//快递信息
}

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

class OrderConfig : IEntityTypeConfiguration<Order>
{
	public void Configure(EntityTypeBuilder<Order> builder)
	{
		builder.ToTable("T_Orders");
		builder.Property(o => o.Address).IsUnicode();
		builder.Property(o => o.Name).IsUnicode();
		builder.HasOne<Delivery>(o => o.Delivery).WithOne(d => d.Order)
			.HasForeignKey<Delivery>(d => d.OrderId);
	}
}
TestDbContext:
using Microsoft.EntityFrameworkCore;

class TestDbContext : DbContext
{
    public DbSet<Delivery> Deliveries { get; set; }
    public DbSet<Order> Orders { get; set; }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        string connStr = "Server=.;Database=demo6;Trusted_Connection=True";
        optionsBuilder.UseSqlServer(connStr);
        optionsBuilder.LogTo(Console.WriteLine);
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);
    }
}
一对多
Article以及ArticleConfig
public class Article
{
	public long Id { get; set; }//主键
	public string Title { get; set; }//标题
	public string Content { get; set; }//内容
	public List<Comment> Comments { get; set; } = new List<Comment>(); //此文章的若干条评论
}

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

class ArticleConfig : IEntityTypeConfiguration<Article>
{
	public void Configure(EntityTypeBuilder<Article> builder)
	{
		builder.ToTable("T_Articles");
		builder.Property(a => a.Content).IsRequired().IsUnicode();
		builder.Property(a => a.Title).IsRequired().IsUnicode().HasMaxLength(255);
	}
}
Comment以及CommentConfig
public class Comment
{
	public long Id { get; set; }
	public Article Article { get; set; }
	public long ArticleId { get; set; }
	public string Message { get; set; }
}


using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

class CommentConfig : IEntityTypeConfiguration<Comment>
{
	public void Configure(EntityTypeBuilder<Comment> builder)
	{
		builder.ToTable("T_Comments");
		builder.HasOne<Article>(c => c.Article).WithMany(a => a.Comments)
			.IsRequired().HasForeignKey(c => c.ArticleId);
		builder.Property(c => c.Message).IsRequired().IsUnicode();
	}
}
TestDbContext
using Microsoft.EntityFrameworkCore;
class TestDbContext : DbContext
{
    public DbSet<Article> Articles { get; set; }
    public DbSet<Comment> Comments { get; set; }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        string connStr = "Server=.;Database=demo3;Trusted_Connection=True";
        optionsBuilder.UseSqlServer(connStr);
        optionsBuilder.LogTo(Console.WriteLine);
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);
    }
}
多对多
Student以及StudentConfig
class Student
{
	public long Id { get; set; }
	public string Name { get; set; }
	public List<Teacher> Teachers { get; set; } = new List<Teacher>();
}

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

class StudentConfig : IEntityTypeConfiguration<Student>
{
	public void Configure(EntityTypeBuilder<Student> builder)
	{
		builder.ToTable("T_Students");
		builder.Property(s => s.Name).IsUnicode().HasMaxLength(20);
		builder.HasMany<Teacher>(s => s.Teachers).WithMany(t => t.Students)
			.UsingEntity(j => j.ToTable("T_Students_Teachers"));
	}
}
Teacher以及TeacherConfig
class Teacher
{
	public long Id { get; set; }
	public string Name { get; set; }
	public List<Student> Students { get; set; } = new List<Student>();
}

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

class TeacherConfig : IEntityTypeConfiguration<Teacher>
{
	public void Configure(EntityTypeBuilder<Teacher> builder)
	{
		builder.ToTable("T_Teachers");
		builder.Property(s => s.Name).IsUnicode().HasMaxLength(20);
	}
}
TestDbContext
using Microsoft.EntityFrameworkCore;

class TestDbContext : DbContext
{
    public DbSet<Student> Students { get; set; }
    public DbSet<Teacher> Teachers { get; set; }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        string connStr = "Server=.;Database=demo7;Trusted_Connection=True";
        optionsBuilder.UseSqlServer(connStr);
        optionsBuilder.LogTo(Console.WriteLine);
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);
    }
}
Program:
using Microsoft.EntityFrameworkCore;

using TestDbContext ctx = new TestDbContext();
foreach (var t in ctx.Teachers.Include(t => t.Students))
{
	Console.WriteLine($"老师{t.Name}");
	foreach (var s in t.Students)
	{
		Console.WriteLine($"---{s.Name}");
	}
}

Include 起到left join 作用

AutoInclude会自动进行include 操作 可能会影响性能,不推荐 感兴趣可以去查看EF Core资料

总结:

HasXXX().WithYYY()理解A有xxx个B对象,B对象中有YYY个A这句话即可 ;

多对多(HasMany,HasMany)在net5.0之前是不能使用的,在5.0之后才能使用

//注意中间表的配置
builder.HasMany<Teacher>(s => s.Teachers).WithMany(t => t.Students)
			.UsingEntity(j => j.ToTable("T_Students_Teachers"));

也可参考地址:https://blog.csdn.net/wsnbbdbbdbbdbb/article/details/122270706