zoukankan      html  css  js  c++  java
  • EF Core 二 、 入门 EF Core (简单操作)

    入门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的其他使用持续进行分析,以及一些高阶应用;

    示例代码地址:https://gitee.com/wuxingquema/knowledge-points

    文章后面附上EFCore的源码地址,一起看源码,一起学习 https://github.com/dotnet/efcore
    帮助博客园推广下:https://www.cnblogs.com/cmt/p/14003277.html

  • 相关阅读:
    Django中MySQL读写分离技术
    BBS+Blog项目开发
    数据算法 --hadoop/spark数据处理技巧 --(5.移动平均 6. 数据挖掘之购物篮分析MBA)
    数据算法 --hadoop/spark数据处理技巧 --(3.左外连接 4.反转排序)
    数据算法 --hadoop/spark数据处理技巧 --(1.二次排序问题 2. TopN问题)
    mysql ---- Host '' is not allowed to connect to this MySQL server
    win 8.0.12
    Transformer 和 Transformer-XL——从基础框架理解BERT与XLNet
    Transformer 详解
    XLNet:运行机制及和Bert的异同比较
  • 原文地址:https://www.cnblogs.com/tiaoshuidenong/p/14009432.html
Copyright © 2011-2022 走看看