入门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. centos8平台redis cluster集群添加/删除node节点(redis5.0.7)

    一,当前redis cluster的node情况: 我们的添加删除等操作都是以这个cluster作为demo cluster采用六台redis,3主3从 redis1 : ip: 172.17.0.2 ...

  2. Redis基础——剖析基础数据结构及其用法

    这是一个系列的文章,打算把Redis的基础数据结构.高级数据结构.持久化的方式以及高可用的方式都讲一遍,公众号会比其他的平台提前更新,感兴趣的可以提前关注,「SH的全栈笔记」,下面开始正文. 如果你是 ...

  3. C++类模板声明与定义为何不能分开

    我们用C++写类的时候,通常会将.cpp和.h文件分开写,即实现和声明分开写了:但在C++的类模板中,这种写法是错误的. 在<C++编程思想>的第16章的"16.3模板语法&qu ...

  4. java默认值

    注意:此处默认值是在类成员时才可以被初始化有默认值 如果时在局部变量中,必须先自己初始化才可以使用,否则编译失败

  5. python提取视频第一帧图片

    一.实现代码 # -*- coding: utf-8 -*- import cv2 from PIL import Image from io import BytesIO def tryTime(m ...

  6. 一起学Vue:入门

    Why-为什么需要Vue? 前端开发存在的问题? 其一,需求变化频率更高 产品功能迭代前端肯定需要跟着调整. 提意见的人多,前端嘛谁都能看得见,所以,谁都可以指手画脚提一点意见.产品经理.项目经理.老 ...

  7. makefile管理项目

    makefile: 管理项目. 命名:makefile Makefile --- make 命令 1 个规则: 目标:依赖条件 (一个tab缩进)命令 1. 目标的时间必须晚于依赖条件的时间,否则,更 ...

  8. 续 Eureka+Hystrix+Zuul(Zuul API网关)

    概述: 服务的合并,转发,验证,异构协议.将上百个请求融为一个发送到后台,返回大的JSON返回处理: 作用:这减少了客户端与应用程序间的交互次数,还简化了客户端代码. Zuul可以通过加载动态过滤机制 ...

  9. 虚拟化下Centos7 扩容根分区

    查看分区大小和挂载情况 用到的命令df.lsblk [root@localhost ~]# df -h Filesystem Size Used Avail Use% Mounted on /dev/ ...

  10. Python3网络学习案例三:编写web server

    1. 写在前面 这里总结的并不够详细,有时间了再进行补充. 2. 设计思路 HTTP协议是建立在TCP上的1. 建立服务器端TCP套接字(绑定ip,port),等待监听连接:listen(2. 打开浏 ...