入门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. ES异常处理-NoNodeAvailableException

    1.问题描述 ES client客户端能创建,但是在用客户端操作时报:NoNodeAvailableException[None of the configured nodes are availab ...

  2. 扫描仪扫描文件处理-A4分辨率

    转换公式:毫米转英寸,英寸乘以DPI(每英寸点数) 1英寸 = 2.54 厘米 = 25.4 毫米 例子(600dpi):mm: 210x297 = px: 4961(210/25.4*600)x70 ...

  3. 【UNR #2】UOJ拯救计划

    UOJ小清新题表 题目内容 UOJ链接 题面太长了(其实是我懒得改LaTeX了) 一句话题意: 给出 \(n\) 个点和 \(m\) 条边,对其进行染色,共 \(k\) 种颜色,要求同一条边两点颜色不 ...

  4. swoft配置连接池

    bean.php 'db' => [ 'class' => Database::class, 'dsn' => 'mysql:dbname=test;host=127.0.0.1', ...

  5. spring boot:使用validator做接口的参数、表单、类中多字段的参数验证(spring boot 2.3.1)

    一,为什么要做参数验证? 永远不要相信我们在后端接收到的数据, 1,防止别人通过接口乱刷服务:有些不怀好意的人或机构会乱刷我们的服务,例如:短信接口, 相信大家可能很多人在工作中遇到过这种情况 2,防 ...

  6. 这玩意比ThreadLocal叼多了,吓得why哥赶紧分享出来。

    这是why哥的第 70 篇原创文章 从Dubbo的一次提交开始 故事得从前段时间翻阅 Dubbo 源码时,看到的一段代码讲起. 这段代码就是这个: org.apache.dubbo.rpc.RpcCo ...

  7. Spring Boot 整合多点套路,少走点弯路~

    持续原创输出,点击上方蓝字关注我 个人原创博客+1,点击前往,查看更多 目录 前言 Spring Boot 版本 找到自动配置类 注意@Conditionalxxx注解 注意EnableConfigu ...

  8. UEditor 自定义图片视频尺寸校验

    UEditor支持单图.多图以及视频上传,编辑器配置项支持文件格式.文件大小校验,对于文件宽高尺寸校验暂不支持.这里记录一下自定义图片.视频尺寸校验过程,内容核心主要是扩展校验逻辑和增加自定义提示文本 ...

  9. Python之数据类型总结

    1.字符串 2.数字 3.列表 4.元组 5.字典 可变 or 不可变 1:可变:列表.字典 2:不可变:字符串,数字,元组 访问顺序 1.直接访问:数字 2.顺序访问:字符串,列表,元组 3.映射访 ...

  10. CTCall简介(后续会继续补充)

    使用CTCall需要导入CoreTelephony.framework框架. CTCall的基本使用 (1)初始化call CFStringRef number = CFSTR("15555 ...