提示:前面的EF Core例子中我们会有很多疑问,比如为什么我们只建立实体类并进行了一些乱七八糟的配置,数据库中就有了对应表?那些表的名字和字段是怎么指定的?在哪指定的?
一,EF Core的实体类配置
EF Core 作为一个ORM框架,它完成了实体类和数据库中表的映射,这里面有着怎样的约定,有着怎样的默认配置?
1.约定大于配置
这个概念的提出我并不意外,之前学Java时,Springboot的核心理念就是约定大于配置,大概意思就是我们会准备一套默认的配置,这是一个约定,当我们不去修改的时候,就会默认,这样会减少很多不必要的简单配置,当然一些需要根据具体业务场景才能决定,这些会有对应的接口提供自定义配置。
在EF Core中,也采用了“约定大于配置”的原则,EF Core会默认按照约定根据实体类以及DbContext的定义类实现和数据库表的映射配置,除非我们显式指定了配置规则,比如上一篇中的ToTable("T_Books")
EF Core中的默认的规则约定有很多,这里只列出一些主要的约定规则
- 数据库表名采用上下文类中对应的DbSet的属性名
- 数据库表列的名字采用实体类属性的名字,列的数据类型采用和实体属性类型兼容的类型
- 数据库表列的可空性取决于对应实体类属性的可空性。EF Core6 中支持C#中的可空引用类型
- 名字为Id的属性为主键,如果主键为short,int或者long类型,则主键默认采用自动增长类型的列
2.EF Core的大概执行过程
C#—>EF Core核心–>AST—> SQL Server EF Core provider —> SQL Server ADO.NET provider
上面的路线大概是我们进行一个检查的查询时EF Core所执行的
C#代表的就是我们编写的查询代码
Article article = context.Articles.Include(a => a.comments).Single(a => a.Id == 1);
Console.WriteLine(article.Id);
Console.WriteLine(article.Title);
foreach(Comment com in article.comments)
{
Console.WriteLine(com.Id+","+com.Message);
}
EF Core核心指的是我们EF Core框架,它把C#代码翻译为AST(抽象语法树),然后把AST,抽象语法树翻译为SQL语句,然后由SQL Server EF Core provider来把SQL放入到SQL Server ADO.NET provider中,然后由ADO.NET来执行SQL。
说到这里,可能还是会有疑问,这些东西都是啥,ADO.NET是就是SQL语句一个简单封装,地位相当与JAVA中的JDBC,而上面的那些东西都是框架,就比如EF Core这个ORM框架类比为Mybatis等持久层…
一、使用代码查看SQL执行语句
示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。
- 标准日志方式
- 需要安装日志包
Install-Package Microsoft.Extensions.Logging.Console
- 需要安装日志包
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EFCoreTest1
{
class MyDbContext:DbContext
{
//使用标准日志
private static ILoggerFactory loggerFactory = LoggerFactory.Create(b=>b.AddConsole());
public DbSet<Book> Books { get; set; }
public DbSet<Person> Persons { get; set; }
public DbSet<Dog> Dogs { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.UseSqlServer("Server=.;Database=demo1;Trusted_Connection=True;MultipleActiveResultSets=true;Encrypt=True;TrustServerCertificate=True;");
//这里使用
optionsBuilder.UseLoggerFactory(loggerFactory);
/*optionsBuilder.LogTo(msg =>
{
if (!msg.Contains("CommandExecuting")) return;
Console.WriteLine(msg);
});*/
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
//从当前程序集中加载所有的IEntityTypeConfiguration
modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);
}
}
}
- 简单日志
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EFCoreTest1
{
class MyDbContext:DbContext
{
//private static ILoggerFactory loggerFactory = LoggerFactory.Create(b=>b.AddConsole());
public DbSet<Book> Books { get; set; }
public DbSet<Person> Persons { get; set; }
public DbSet<Dog> Dogs { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.UseSqlServer("Server=.;Database=demo1;Trusted_Connection=True;MultipleActiveResultSets=true;Encrypt=True;TrustServerCertificate=True;");
//optionsBuilder.UseLoggerFactory(loggerFactory);
//简单日志
optionsBuilder.LogTo(msg =>
{
if (!msg.Contains("CommandExecuting")) return;
Console.WriteLine(msg);
});
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
//从当前程序集中加载所有的IEntityTypeConfiguration
modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);
}
}
}
- ToQueryString
IQueryable<Book> books = myDbContext.Books.Where(p => p.AuthorName == "杨中科" && p.Title == "程序员的SQL金典");
//这里是
string sql = books.ToQueryString();
Console.WriteLine("这就是我想要的!" + sql);