Entity Framework Core——1.快速开始

https://docs.microsoft.com/zh-cn/ef/core/dbcontext-configuration/
https://www.entityframeworktutorial.net/basics/how-entity-framework-works.aspx

本文是系列文章的第一篇,所有文章可点击页面专栏查看。

1.快速开始

假如有以下的数据模型:
image

分别创建实体如下:

public class Student
{
        public int ID { get; set; }
        public string LastName { get; set; }
        public string FirstMidName { get; set; }
        public DateTime EnrollmentDate { get; set; }

        public ICollection<Enrollment> Enrollments { get; set; }
}

默认情况下,EF Core 将名字为ID或者ClassnameID的属性视为主键,所以这里的ID或者StudentID都可以为主键。Enrollments导航属性,导航属性中包含与此实体相关的其它实体。Enrollments属性定义为ICollection<Enrollment>,也可以使用List<Enrollment>HashSet<Enrollment>等集合类型。使用ICollection<Enrollment>时,EF Core会默认创建HashSet<Enrollment>集合。

    public class Course
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int CourseID { get; set; }
        public string Title { get; set; }
        public int Credits { get; set; }

        public ICollection<Enrollment> Enrollments { get; set; }
    }

可以通过DatabaseGenerated特性指定主键,无需靠数据库生成。

    public class Enrollment
    {
        public int EnrollmentID { get; set; }
        public int CourseID { get; set; }
        public int StudentID { get; set; }
        public int? Grade { get; set; }

        public Course Course { get; set; }
        public Student Student { get; set; }
    }
  1. StudentID是外键,对应的导航属性是Student。如果一个属性的名称符合<导航属性名称><导航属性对应实体的主键属性名>,则EF会自动将其视为外键。
  2. 另外如果属性名为<导航属性对应实体的主键属性名>也可以是外键。例如上面代码的CourseID,因为Course实体的主键就是叫CourseID

这里以SqlServer数据库为例,从nuget里添加Microsoft.EntityFrameworkCore.SqlServer provider,其他数据库的provider下文有给出。

appsettings.json里添加连接字符串ConnectionStrings

{
  ....
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "SchoolContext": "Server=(localdb)\\mssqllocaldb;Database=CU-1;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

创建数据库上下文SchoolContext

public class SchoolContext : DbContext
{
        public SchoolContext (DbContextOptions<SchoolContext> options)
            : base(options)
        {
            //确保数据库被创建,如果有了这个数据库此方法不会执行任何操作即使数据库结构不正确。如果没有数据库,则按当前实体架构创建数据库。
            this.Database.EnsureCreated();
        }

        public DbSet<Student> Students { get; set; }
        public DbSet<Enrollment> Enrollments { get; set; }
        public DbSet<Course> Courses { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Course>().ToTable("Course");
            modelBuilder.Entity<Enrollment>().ToTable("Enrollment");
            modelBuilder.Entity<Student>().ToTable("Student");
        }
}

将数据库上下文服务注入到容器:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<SchoolContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("SchoolContext")));
    //添加数据库异常筛选器,需要nuget包 Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
    services.AddDatabaseDeveloperPageExceptionFilter();
}

获取连接字符串时也可以写成services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer("name=ConnectionStrings:DefaultConnection"));

2.EF是怎么工作的

在这里插入图片描述

EF的主要工作任务有:

  • 映射实体类的结构到对应的数据库结构上
  • LINQ查询翻译为sql并执行
  • 跟踪实体类数据的改变,当调用SaveChanges方法时把这些改变翻译成sql保存到数据库。

2.1 实体数据模型(EDM)是什么

在这里插入图片描述

EF在开始工作前的第一项任务就是创建实体数据模型(Entity Data Model,EDM)以后简称模型。EDM是一种存在于内存中的数据结构,是实体类于数据库表映射的桥梁,包含以下三部分:

  • Conceptual Model (概念模型):ef会为实体类、数据库上下文类、默认约定、配置等创建概念模型
  • Storage Model (存储模型):可以理解为数据库结构。当使用code-first模式时,从概念模型推断。当使用database-first时,从目标数据库推断。
  • Mappings (映射):负责维护概念模型与存储模型之间的转换关系

2.2 查询和保存的处理过程

查询:EDM将linq翻译成sql,然后将数据库返回的数据翻译成实体对象
在这里插入图片描述

保存:EDM将改变的数据的翻译成sql
在这里插入图片描述

2.3 EF怎么知道SaveChanges时哪些内容要提交到数据库?

通过Change tracking实现的。当数据从数据库读取出来之后,EF会创建数据的快照,调用保存时会与快照进行对比。

3.EF Core的配置和初始化

除了DI容器可以初始化context外也还可以手动new DbContext创建,适用于控制台、WinForm、WPF等程序。

3.1 使用new来初始化

通过重写OnConfiguring方法将配置项传递到context里,可以使用new的方式来手动初始化context。

public class ApplicationDbContext : DbContext
{
    private readonly string _connectionString;
    public ApplicationDbContext(string connectionString)
    {
        _connectionString = connectionString;
    }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(_connectionString);
    }
}

如果不重写OnConfiguring方法也可以new对象。使用DbContextOptionsBuilder创建DbContextOptions 对象,然后将这个对象传递到上述章节的SchoolContext里。这样通过依赖关系注入配置的context也可以显式构造,如

var contextOptions = new DbContextOptionsBuilder<SchoolContext>()
    .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test")
    .Options;

using var context = new SchoolContext(contextOptions);

3.2 配置EF Core

所有context配置的起点都是DbContextOptionsBuilder,可以通过以下三种方式获取这个builder:

  • AddDbContext方法中入参,上一小节已展示
  • override的OnConfiguring方法,上一小节已展示
  • 使用new显式构造,上一小节已展示

此外无论通过何种方式构造dbcontext,其OnConfiguring方法都会被执行。

3.3 配置数据库提供程序

每个dbcontext只能使用一个数据库提供程序。使用特定的Use***方法配置数据库提供程序,这些Use***方法一般都在对应的nuget包里。如果要用sqlserver:

public class ApplicationDbContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test");
    }
}

常见的数据库提供程序有以下几种:

数据库配置示例NuGet包
SQL Server 或 Azure SQL.UseSqlServer(connectionString)Microsoft.EntityFrameworkCore.SqlServer
Azure Cosmos DB.UseCosmos(connectionString, databaseName)Microsoft.EntityFrameworkCore.Cosmos
SQLite.UseSqlite(connectionString)Microsoft.EntityFrameworkCore.Sqlite
EF Core 内存中数据库.UseInMemoryDatabase(databaseName)Microsoft.EntityFrameworkCore.InMemory
PostgreSQL.UseNpgsql(connectionString)Npgsql.EntityFrameworkCore.PostgreSQL
MySQL/MariaDB.UseMySql((connectionString)Pomelo.EntityFrameworkCore.MySql
Oracle.UseOracle(connectionString)Oracle.EntityFrameworkCore

DbContextOptionsBuilder其它常见配置项:

DbContextOptionsBuilder方法作用了解更多
UseQueryTrackingBehavior设置查询的默认跟踪行为查询跟踪行为
LogTo获取 EF Core 日志的一种简单方法(EF Core 5.0 及更高版本)日志记录、事件和诊断
UseLoggerFactory注册 Microsoft.Extensions.Logging 工厂日志记录、事件和诊断
EnableSensitiveDataLogging在异常和日志记录中包括应用程序数据日志记录、事件和诊断
EnableDetailedErrors更详细的查询错误(以性能为代价)日志记录、事件和诊断
ConfigureWarnings忽略或引发警告和其他事件日志记录、事件和诊断
AddInterceptors注册 EF Core 侦听器日志记录、事件和诊断
UseLazyLoadingProxies使用动态代理进行延迟加载延迟加载
UseChangeTrackingProxies使用动态代理进行更改跟踪即将推出…
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
System.InvalidOperationException: The LINQ expression 'DbSet<z_tjdj_yydj>() .Where(z => z.YYBH.Substring( startIndex: 0, length: z.YYBH.Length - 6) == __Substring_0) .Max(z => int.Parse(z.YYBH.Substring( startIndex: 10, length: 5)))' could not be translated. Additional information: Translation of method 'int.Parse' failed. If this method can be mapped to your custom function, see https://go.microsoft.com/fwlink/?linkid=2132413 for more information. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information. at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.<VisitMethodCall>g__CheckTranslated|15_0(ShapedQueryExpression translated, <>c__DisplayClass15_0& ) at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression) at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor) at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node) at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query) at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async) at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async) at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass9_0`1.<Execute>b__0() at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler) at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query) at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression) at System.Linq.Queryable.Max[TSource,TResult](IQueryable`1 source, Expression`1 selector) at VOL.TJYY.Services.z_tjdj_yydjService.<>c__DisplayClass10_0.<Import1>b__0(List`1 list) at VOL.Core.BaseProvider.ServiceBase`2.Import(List`1 files) in D:\work\TJYYHT_VOL\Net6版本\VOL.Core\BaseProvider\ServiceBase.cs:line 459 at VOL.TJYY.Services.z_tjdj_yydjService.Import(List`1 files) at VOL.TJYY.Services.z_tjdj_yydjService.Import1(List`1 fileInput, Dictionary`2 data) at VOL.TJYY.Controllers.z_tjdj_yydjController.Import1(List`1 fileInput, Dictionary`2 data) at lambda_method901(Closure , Object , Object[] ) at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync() at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()
06-10

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JimCarter

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值