入门EF Core

我们将开始真正的EF之旅了,这里使用SqlServer数据,然后DbFirst;

为嘛使用SqlServer,目前公司的整体业务全部在SqlSever,所以很多产品业务都是依托于这个,当然也在考虑做数据库切换,切换EF Core就是开始,为后续做好准备,目前SqlServer的linux集群部署太麻烦了,至少我是这样认为的,而且很多客户也都人格上排斥 .... 说多了都是泪 ....

然后就是DbFirst,公司是业务型公司,注重业务需求的设计,所以在需求开发之前,表结构的设计基本上都已经确定,基于现在的业务以及背景,可能DbFirst更加适合,当然Code First也不会丢掉的

一、安装 EF Core

新建类库,用来引用 Microsoft.EntityFrameworkCore.SqlServer



如果在项目中有类似的第三方程序集引用,建议放入统一的程序集,这样不用到处维护引用信息;而且有利于后期解耦,其他业务相关的都依赖统一接口就可以,这样具体的实现引用只是一个插件而已;

二、生成数据表结构

为了做测试,这里生成两张表,TestTable,以及TestTableDetail,用来模拟主从表的场景;一步步来啊

CREATE TABLE [dbo].[TestTable](
        [Id] [INT] NOT NULL,
        [Name] [NVARCHAR](200) NOT NULL,
PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE TABLE [dbo].[TestTableDetail](
        [Id] [INT] NOT NULL,
        [PID] [INT] NOT NULL,
        [Name] [NVARCHAR](200) NOT NULL,
PRIMARY KEY CLUSTERED
(
        [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

三、建立实体对象

建立实体对象,用来与数据库的对象进行匹配

 [Table("TestTable")]
    public class TestTable
    {
        [Key]
        public int Id { get; set; }
        public string Name { get; set; }
    }      [Table("TestTableDetail")]
    public class TestTableDetail
    {
        [Key]
        public int Id { get; set; }
        public int PID { get; set; }
        public string Name { get; set; }
    }

四、创建DbContext上下文

    /// <summary>
    /// 自定义 数据上下文
    /// </summary>
    public class MyDbContext : DbContext
    {
        public DbSet<TestTable> TestTables { get; set; }
        public DbSet<TestTableDetail> TestTableDetails { get; set; }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            //写入连接字符串
   optionsBuilder.UseSqlServer("Data Source=.\\SQLSERVER2014;Initial Catalog=EfCore.Test;User ID=sa;Pwd=1");
        }
    }

DbContext是EF操作数据库的窗口,我们将为每个表来创建一个DbSet<>泛型类属性,用来操作具体的表对象;DbSet支持Linq操作;这里两个知识点:

1.如何配置连接字符串

如果是Asp.net Core程序,通常配置在Startup.cs中,需要导入 Microsoft.Extensions.Configuration 名命空间方可使用,按如下方式进行注册

public void ConfigureServices(IServiceCollection services) { services.AddDbContext<BloggingContext>(options =>       options.UseSqlServer(Configuration.GetConnectionString("BloggingDatabase")));
}

看下源码

EFCore.SqlServer

public static DbContextOptionsBuilder UseSqlServer(
            [NotNull] this DbContextOptionsBuilder optionsBuilder,
            [NotNull] string connectionString,
            [CanBeNull] Action<SqlServerDbContextOptionsBuilder> sqlServerOptionsAction =
null)
        {
            Check.NotNull(optionsBuilder, nameof(optionsBuilder));
            Check.NotEmpty(connectionString, nameof(connectionString));
            var extension =
(SqlServerOptionsExtension)GetOrCreateExtension(optionsBuilder).WithConnectionString(connectionString);          
((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension);
            ConfigureWarnings(optionsBuilder);
            sqlServerOptionsAction?.Invoke(new
SqlServerDbContextOptionsBuilder(optionsBuilder));
            return optionsBuilder;
        }

对DbContextOptionsBuilder进行扩展,提供了UseSqlServer方法,连接信息的提供都是通过 DbContextOptionsBuilder 来实现

针对WinForms以及WPF应用呢?我测试验证的就是控制台应用

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
//写入连接字符串
optionsBuilder.UseSqlServer("Data Source=.\\SQLSERVER2014;Initial Catalog=EfCore.Test;User ID=sa;Pwd=1");
}

这里我是固定了连接字符串,可以根据配置文件来写入了;可以看到也是对 DbContextOptionsBuilder 的 UseSqlSerer方法的调用;

查看源码:

DbContext

//定义虚方法OnConfiguring的位置
protected internal virtual void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
        }

在InternalServiceProvider中进行了初始化调用,调用了OnConfiguring,从而进行了连接字符串的赋值;

2.是否需要为每个类都定义DbSet属性

如果业务系统过大,我们真的会定义一个DbContext,然后将所有Entity定义成DbSet<>?应该不会,这时我们可以通过反射来实现;

1.通过实现一个反射读取类,来动态读取实体类,也就是读取类具备 “Table”属性的目标类,或者自己集成一个父类用来识别实体类;

2.将读取到的实体类,动态加入到DbContext的实体模型中;

通过 重写 OnModelCreating 方法;微软官方文档地址:https://docs.microsoft.com/zh-cn/ef/core/modeling/

通过调用ModelBuilder.Entity方法直接贴代码:

    /// <summary>
    /// 自定义 数据上下文
    /// </summary>
    public class DynamicDbContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            //写入连接字符串
            optionsBuilder.UseSqlServer("Data Source=.\\SQLSERVER2014;Initial Catalog=EfCore.Test;User ID=sa;Pwd=1");
        }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            var assembly = Assembly.GetExecutingAssembly();
            foreach (Type type in assembly.ExportedTypes)
            {
                if (type.IsClass && type != typeof(EntityBase) && typeof(EntityBase).IsAssignableFrom((Type) type))
                {
                    var method = modelBuilder.GetType().GetMethods().FirstOrDefault(x => x.Name == "Entity");
                    if (method != null)
                    {
                        method = method.MakeGenericMethod(type);
                        method.Invoke(modelBuilder, null);
                   }
                }
            }
            base.OnModelCreating(modelBuilder);
        }
    }

整体思路还是两步走,先找到实体的实现类,然后通过调用DbContenxt的Entity方法;我们来看下DbContext源码;



最后通过Metadata.AddEntityType加入到实体模型,Metadata用来存储实体元数据;

还有两外一种实现方式,其实也就是衍生的方式了,因为查看源码得知最后实体被加入到了Medel中,那何不直接加入呢?



调用代码:

            var myDbContext = new DynamicDbContext();
            var list = myDbContext.Set<TestTable>().ToList();
            Console.WriteLine($"TestTable Count: {list.Count}");
            if (!list.Any()) return;
            Console.WriteLine($"TestTable Detail ----------------  ");
            foreach (var item in list)
            {
                Console.WriteLine($"ID : {item.Id} , Name : {item.Name}");
            }
            Console.WriteLine($"------------------------");

来看下执行效果吧....

这里的实现让我想到了ABP数据仓储的实现,ABP为每个实体创建一个仓储对象,不需要手动一个个创建,可以查看我的ABP系列 => ABP 数据访问 - IRepository 仓储 ,可以参考ABP仓储管理的思想;大家也可以去看下

五、数据访问

好了,回到最初的实现思路上,前面的准备工作都做的差不多了,该正式跑一把数据了....

public static void Query_查询数据_全量查询()
        {
            var myDbContext = new MyDbContext();
            var list = myDbContext.TestTables.ToList();
            Console.WriteLine($"TestTable Count: {list.Count}");
            if (!list.Any()) return;
            Console.WriteLine($"TestTable Detail ----------------  ");
            foreach (var item in list)
            {
                Console.WriteLine($"ID : {item.Id} , Name : {item.Name}");
            }
            Console.WriteLine($"------------------------");
        }

通过控制台应用,执行上述方法,即可查询到TestTable中的数据



到此我们基本就开始使用EF Core,实现了数据访问;后续将开始对EF的其他使用持续进行分析,以及一些高阶应用;

文章后面附上EFCore的源码地址,一起看源码,一起学习 https://github.com/dotnet/efcore

帮助博客园推广下:https://www.cnblogs.com/cmt/p/14003277.html

EF Core 二 、 入门 EF Core的更多相关文章

  1. K8S+GitLab-自动化分布式部署ASP.NET Core(二) ASP.NET Core DevOps

    一.介绍 前一篇,写的K8S部署环境的文章,简单的介绍下DevOps(Development和Operations的组合词),高效交付, 自动化流程,来减少软件开发人员和运维人员的沟通.Martin ...

  2. EF Core 快速上手——EF Core 入门

    EF Core 快速上手--EF Core 介绍 本章导航 从本书你能学到什么 对EF6.x 程序员的一些话 EF Core 概述 1.3.1 ORM框架的缺点 第一个EF Core应用   本文是对 ...

  3. asp.net core系列 30 EF管理数据库架构--必备知识 迁移

    一.管理数据库架构概述 EF Core 提供两种主要方法来保持 EF Core 模型和数据库架构同步.一是以 EF Core 模型为基准,二是以数据库为基准. (1)如果希望以 EF Core 模型为 ...

  4. EF Core 快速上手——EF Core的三种主要关系类型

    系列文章 EF Core 快速上手--EF Core 入门 本节导航 三种数据库关系类型建模 Migration方式创建和习修改数据库 定义和创建应用DbContext 将复杂查询拆分为子查询   本 ...

  5. asp.net core系列 31 EF管理数据库架构--必备知识 反向工程

    一.   反向工程 反向工程是基于数据库架构,生成的实体类和DbContext类代码的过程,对于Visual Studio开发,建议使用PMC.对于其他开发环境,请选择.NET Core CLI工具( ...

  6. asp.net core 系列 20 EF基于数据模型创建数据库

    一.概述 本章使用 Entity Framework Core 构建执行基本数据访问的 ASP.NET Core MVC 应用程序.使用迁移(migrations)基于数据模型创建数据库,是一种cod ...

  7. EF 6.x、EF Core实现dynamic动态查询和EF Core实现多个上下文实例池你了解多少?

    前言 很长一段时间没有写博客了,今天补上一篇吧,偶尔发现不太愿意写博客了,太耗费时间,不过还是在坚持当中,毕竟或许写出来的东西能帮到一些童鞋吧,接下来我们直奔主题.无论是在在EF 6.x还是EF Co ...

  8. 讨论过后而引发对EF 6.x和EF Core查询缓存的思考

    前言 最近将RabbitMQ正式封装引入到.NET Core 2.0项目当中,之前从未接触过是个高大上的东东跟着老大学习中,其中收获不少,本打算再看看RabbitMQ有时间写写,回来后和何镇汐大哥探讨 ...

  9. Asp.Net Core WebAPI入门整理(二)简单示例

    一.Core WebAPI中的序列化 使用的是Newtonsoft.Json,自定义全局配置处理: // This method gets called by the runtime. Use thi ...

随机推荐

  1. gin教程

    Golang Gin 实战(十)| XML渲染 Golang Gin 实战(九)| JSONP跨域和劫持 Golang Gin 实战(八)| JSON渲染输出 Golang Gin 实战(七)| 分组 ...

  2. nginx给consul集群配置负载均衡

    upstream consul { server 127.0.0.1:8501; server 127.0.0.1:8502; server 127.0.0.1:8503; } server { li ...

  3. SpringApplication.run(xxx.class, args)背后的东东——整体脉络

    从spring到springmvc,再到springboot.springcloud,应用程序api开发调用方面都已经非常熟悉,但对spring背后的扩展机制:为何一个简单的main方法可以实现这么强 ...

  4. C# stopwatch的简单使用(计算程序执行时间)

    首先添加引用 using System.Diagnostics;//stopwatch的引用 //声明变量 Stopwatch a=new Stopwatch();//PS:这里一定要new(实例化) ...

  5. Linux 环境编程:dirfd参数 有关解析

    背景 在Unix环境编程中,系统提供了很多以at结尾的函数,如openat.fstatat等,而这类函数通常有一个特点,就是形参列表中多了int dirfd 例如: int open(const ch ...

  6. 常用命令--windows

    查看端口号是否占用并杀进程 1 netstat -ano | findstr " " 2 tasklist | findstr " " 3 taskkill / ...

  7. pycharm pro2020版专业版永久激活

    pycharm2020版本专业版永久激活[亲测有效] pycharm2020.1版安装包与破解工具下载 可私信我获取资源. 公众号,轻松学编程 教程 1.先下载安装包和破解补丁压缩包,然后点击pych ...

  8. layui table中固定表头,弹框缩放之后,表头对不齐问题

    新手一枚  直接上解决方案 在layui弹出成功后再渲染表格数据 具体操作就是在layer弹层完成之后的回调中渲染表格数据 layer.open({ type: 1, content:  $(&quo ...

  9. 深入web workers (上)

    前段时间,为了优化某个有点复杂的功能,我采用了shared workers + indexDB,构建了一个高性能的多页面共享的服务.由于是第一次真正意义上的运用workers,比以前单纯的学习有更多体 ...

  10. 1、Web应用

    一 Web应用的组成 接下来我们学习的目的是为了开发一个Web应用程序,而Web应用程序是基于B/S架构的,其中B指的是浏览器,负责向S端发送请求信息,而S端会根据接收到的请求信息返回相应的数据给浏览 ...