第二十三节:EFCore6.0反向测试、增删改查、主键问题、EFCore操作DB原理 、翻译输出SQL的3种方式

一. EFCore6.0反向测试

1. 需要的程序集

   必须的程序集:  Microsoft.EntityFrameworkCore.Tools

   EF自身的程序集:Microsoft.EntityFrameworkCore

          Microsoft.EntityFrameworkCore.SqlServer

PS:【Microsoft.EntityFrameworkCore.SqlServer】:里面包含【Microsoft.EntityFrameworkCore.Relational】,而它里面又包含:【Microsoft.EntityFrameworkCore】

2. 常用指令

(1).全表的首次映射:

【Scaffold-DbContext "Server=localhost;Database=EFCore6xDB;User ID=sa;Password=123456;" Microsoft.EntityFrameworkCore.SqlServer  -OutputDir Models -Context EFCore6xDBContext -UseDatabaseNames -DataAnnotations -NoPluralize】

(2).全表的后续修改:

【Scaffold-DbContext "Server=localhost;Database=EFCore6xDB;User ID=sa;Password=123456;" Microsoft.EntityFrameworkCore.SqlServer  -OutputDir Models -Context EFCore6xDBContext -UseDatabaseNames -DataAnnotations -Force -NoPluralize】

更多指令参考:https://www.cnblogs.com/yaopengfei/p/11633385.html

 

二. 增删改查

  直接上代码,没啥可说的

 代码分享:

#region 1.1 新增
//{
//    using var db = new EFCore6xDBContext();
//    UserInfo user = new UserInfo()
//    {
//        id = Guid.NewGuid().ToString("N"),
//        userName = "ypf1",
//        userPwd = "123456",
//        userAge = 19,
//        userGender = "男",
//        addTime = DateTime.Now,
//        delflag = 0
//    };
//    await db.Set<UserInfo>().AddAsync(user);
//    await db.SaveChangesAsync();
//    Console.WriteLine("新增成功");

//}
#endregion

#region 1.2 修改
//{
//    using var db = new EFCore6xDBContext();
//    var userList = db.Set<UserInfo>().ToList();
//    foreach (var item in userList)
//    {
//        item.addTime = DateTime.Now;
//        item.delflag++;
//    }
//    await db.SaveChangesAsync();
//    Console.WriteLine("修改成功");

//}
#endregion

#region 1.3 查询
//{
//    using var db = new EFCore6xDBContext();
//    var userList = db.Set<UserInfo>().ToList();
//    foreach (var item in userList)
//    {
//        Console.WriteLine($"{item.userName}, {item.userPwd}, {item.userAge},{ item.userGender}, {item.addTime}, {item.delflag}");
//    }
//}
#endregion

#region 1.4 删除
//{
//    using var db = new EFCore6xDBContext();
//    var user = db.Set<UserInfo>().Where(u => u.userName.StartsWith("ypf")).FirstOrDefault();
//    db.Remove(user);
//    await db.SaveChangesAsync();
//    Console.WriteLine("删除成功");
//}
#endregion
View Code

 

 

三. 主键问题

1. 常用的主键类型

 (1).自增: 数据库中对应int

 (2).Guid: C#代码 Guid.NewGuid();  数据库中对应uniqueidentifier类型

 (3).32位字符串:C#代码Guid.NewGuid().ToString("N");    数据库中对应varchar(32)

 (4).Hi/Lo算法

2. 自增主键剖析

 优点:简单;

 缺点:数据库迁移以及分布式系统中比较麻烦;并发性能差。long、int等类型主键,默认是自增。因为是数据库生成的值,所以SaveChanges后会自动把主键的值更新到Id属性。

       自增字段的代码中不能为Id赋值,必须保持默认值0,否则运行的时候就会报错,要想获取id值,必须借助事务,在savechange之后才能获取,代码麻烦

 

3. Guid剖析

 说明:Guid算法(或UUID算法)生成一个全局唯一的Id。适合于分布式系统,在进行多数据库数据合并的时候很简单。

 优点:简单,高并发,全局唯一;

 缺点:① 磁盘空间占用大

           ② Guid值不连续。使用Guid类型做主键的时候,不能把主键设置为聚集索引。因为聚集索引是按照顺序保存主键的,因此用Guid做主键性能差。比如MySQL的InnoDB引擎中主键是强制使用聚集索引的。有的数据库支持部分的连续Guid,比如SQLServer中的NewSequentialId(),但也不能解决问题。

注意:在SQLServer等中,不要把Guid主键设置为聚集索引;在MySQL中,插入频繁的表不要用Guid做主键。

实操:Guid既可以让EF Core自动赋值,也可以手动赋值,推荐手动赋值

#region 1.Guid可以使用EFCore默认赋值(EFCore6.0不支持了,前后生成的都是00-00-00-00)
{
    Console.WriteLine("-----------1.Guid可以使用EFCore默认赋值---------------");

    using var db = new EFCore6xDBContext();
    RoleInfo role = new RoleInfo()
    {
        roleName = "admin",
        roleMsg = "hhh",
        addTime = DateTime.Now,
        delflag = 0,
    };
    Console.WriteLine($"保存前的id值为:{role.id}");
    db.Set<RoleInfo>().Add(role);
    db.SaveChanges();
    Console.WriteLine($"保存后的id值为:{role.id}");

}
#endregion


#region 2.Guid可以手动赋值
{
    Console.WriteLine("-----------2.Guid可以手动赋值---------------");

    using var db = new EFCore6xDBContext();
    RoleInfo role = new RoleInfo()
    {
        id = Guid.NewGuid(),
        roleName = "admin",
        roleMsg = "hhh",
        addTime = DateTime.Now,
        delflag = 0,
    };
    Console.WriteLine($"保存前的id值为:{role.id}");
    db.Set<RoleInfo>().Add(role);
    db.SaveChanges();
    Console.WriteLine($"保存后的id值为:{role.id}");

}
#endregion

 

4. 32位字符串

  相当于把上述的直接使用Guid做主键的模式进行转换了一下,避免上述聚集索引的问题,当数据量小的时候,使用没问题,数据量大,不如自增查询、插入快。

  截图:https://www.cnblogs.com/yaopengfei/p/14082555.html  中的灵魂拷问

 

5. Hi/Lo算法

   EF Core支持Hi/Lo算法来优化自增列。主键值由两部分组成:高位(Hi)和低位(Lo),高位由数据库生成,两个高位之间间隔若干个值,由程序在本地生成低位,低位的值在本地自增生成。

   不同进程或者集群中不同服务器获取的Hi值不会重复,而本地进程计算的Lo则可以保证可以在本地高效率的生成主键值。但是HiLo算法不是EF Core的标准。

 

6. 混合自增和Guid(非复合主键)

  用自增列做物理的主键,而用Guid列做逻辑上的主键。把自增列设置为表的主键,而在业务上查询数据时候把Guid当主键用。

  在和其他表关联以及和外部系统通讯的时候(比如前端显示数据的标识的时候)都是使用Guid列。不仅保证了性能,而且利用了Guid的优点,而且减轻了主键自增性导致主键值可被预测带来的安全性问题。

 

四. EFCore操作DB原理

 EFCore是将C#代码翻译成SQL语句,然后交给Ado.Net core 进行操作数据库的

   

     

 

五. 翻译输出SQL的3种方式

1. 标准日志

(1). 依赖程序集

  【Microsoft.Extensions.Logging.Debug】   指的是调试模式下,在vs的输出窗口的输出(适用于各种类型项目的调试, 多用于web项目)

  【Microsoft.Extensions.Logging.Console】 指的是控制台程序中输出。

(2). 需要添加的代码

   protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer("Server=localhost;Database=EFCore6xDB;User ID=sa;Password=123456;");
            //方式1:使用标准日志
            optionsBuilder.UseLoggerFactory(LoggerFactory.Create(build =>
            {
                build.AddConsole();  // 用于控制台程序的输出
                build.AddDebug();    // 用于VS调试,输出窗口的输出
            }));
        }

2. 简单日志

  不需要单独引入程序集了,用系统默认的日志即可

  默认输出的内容很多,所以要加一层判断,仅输出sql语句即可

添加代码:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer("Server=localhost;Database=EFCore6xDB;User ID=sa;Password=123456;");
            //方式2:使用系统日志
            optionsBuilder.LogTo(msg =>
            {
                //if (!msg.Contains("CommandExecuting"))
                //{
                //    return;
                //}
                //Console.WriteLine(msg);
                if (msg.Contains("CommandExecuting")||msg.Contains("Sql"))
                {
                    Console.WriteLine(msg);
                }
            });
        }

3. 方法直接输出

  IQueryable有扩展方法ToQueryString()可以获得SQL。不需要真的执行查询才获取SQL语句;只能获取查询操作的。

{
    using var db = new EFCore6xDBContext();
    var sql = db.Set<UserInfo>().ToQueryString();
    Console.WriteLine(sql);
}

 

 

 

 

 

!

  • 作       者 : Yaopengfei(姚鹏飞)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 声     明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
  • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
 
posted @ 2022-06-10 09:27  Yaopengfei  阅读(959)  评论(1编辑  收藏  举报