EF Core的使用

什么是EF

Entity Framework (EF) Core 是轻量化、可扩展、开源和跨平台版的常用 Entity Framework 数据访问技术。
EF Core 可用作对象关系映射程序 (O/RM),以便于 .NET 开发人员能够使用 .NET 对象来处理数据库,这样就不必经常编写大部分数据访问代码了。core不像framwork一样可以在项目信件中直接选择ado.net实体数据模型。如下
说简单点,就是在我们做增删改查的时候,不用再写非常繁琐的SQL语句,
在以前,我们写完SQL语句后,查询出来的数据还要手动映射为我们的实体类。但现在,这些东西由EF来帮我们完成

 

安装EF Core
我们使用NuGet程序包来安装EF Core所需要的包
右键项目> 管理NuGet程序包

Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Tools (EF工具包,创建实体)

安装完成之后,我们打开程序包管理控制台
工具>NuGet程序包管理器>程序包管理控制台
打开控制台后输入以下命令:
Scaffold-DbContext -Force “Server=LAPTOP-FPRJ0F62\SQLEXPRESS;Database=ShopDB;uid=sa;Password=123;” Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models/DataModels
命令格式:

Scaffold-DbContext -Force “Server=服务器名;Database=数据库名;uid=账户;Password=密码;” (EF组件名)Microsoft.EntityFrameworkCore.SqlServer -OutputDir (实体类存储位置)Models/DataModels

 

执行命令后,系统会自动根据表创建实体类
这里系统会创建一个继承了DBConext类的ShopDBContext,这个ShopDBContext是根据你的数据库名生成的,这个类是连接数据库的桥梁

使用EF Core增删改查
单表查询
这里我们创建一个asp.net mvc类型的项目
查询数据非常简单

class Program
{
  static void Main(string[] args)
  {
  GetProductList();
  }
//获取所有产品
  public static void GetProductList()
  {
    using (ShopDBContext db=new ShopDBContext())
    {
      var produces = db.Products;
      Console.WriteLine("编号\t产品名称");
      foreach (var item in produces)
      {
        Console.WriteLine("{0}\t{1}",item.Id,item.Name);
      }
    }
  }
}

 



执行结果:

在执行db.Products的时候,EF并不会立即去数据库查询,他是先定义好了一组SQL语句,当遇到ToList()或者是循环的时候,他才会去数据库查询数据

插入数据

public static void InsertProduct()
{
  using (ShopDBContext db = new ShopDBContext())
  {
    //实例化一个Products 类,数据库的ID是自增的,所以新增数据的时候,不需要添加ID
    Products products = new Products()
    {
      Name = "C#从入门到精通"
    };
    //添加一行数据
    db.Products.Add(products);
    //只有在执行db.SaveChanges()的时候,才会去保存数据
    //db.SaveChanges会返回受影响行数
    int res= db.SaveChanges();
    Console.WriteLine(res);
  }


}

 



执行结果:

新增数据成功,新增数据的时候一定要db.SaveChanges,切记切记

修改数据
我们就修改下我们刚刚新增的数据
在修改数据的时候,要先查询出数据,EF要确保数据库有这条数据才去修改

public static void UpdateProduct()
{
  using (ShopDBContext db = new ShopDBContext())
  {
    //Find()可以按照ID查询数据
    Products products = db.Products.Find(11);
    //修改数据
    products.Remark = "C#从入门到入坟";
    products.Price = 30;
    //保存数据
    int res = db.SaveChanges();
    Console.WriteLine(res);

  }
}

 



在修改的时候,就不需要执行db.Products.Add();
执行结果:

 

删除数据
和修改数据一样,我们要先从数据库查询出这条数据,然后在进行删除

public static void DeleteProduct()
{
    using (ShopDBContext db = new ShopDBContext())
    {
        //Find()可以按照ID查询数据
        Products products = db.Products.Find(11);
      db.Remove(products);
      //保存数据
      int res = db.SaveChanges();
      Console.WriteLine(res);

  }
}        

 



使用db.Remove(products);删除数据

 

EF Core获取数据库时间

 var serverDateTime = Db.Set<实体>().Select(s => DateTime.Now).First();

 EF Core执行原生SQL

context.Database.ExecuteSqlInterpolated(原生sql);

或者直接查询实体,可以

  context.ProductImgs.FromSqlInterpolated($"原生sql语句");

这样用实体点出来的查询执行之后返回结果就是实体

 EF悲观并发锁

  所谓的EF悲观并发锁,其实是利用数据库本身的一个锁,来实现的一种并发控制,

  EF悲观并发锁代表的就是当多个请求同时需要操作表中的某条数据的时候,假设每次都是多个请求一起。那么需要解决数据不一致的问题。

  1、在查询开始之前,开启一个事务,然后给这个数据添加一个锁,至于是表锁还是行锁,看具体的业务需求,

  2、从查询开始,到最后提交,在完成所有操作之后,SaveChanges()保存之后,提交事务Commit()才释放该锁

  该悲观锁不推荐使用,会有很多问题。

EF乐观并发控制

乐观并发控制的实现原理是:

1、EF的乐观并发控制是不加锁,而是在每一次修改的时候,条件后面带上被修改的值,列如:

//假如首先执行了第一个语句
Update User set name='张三' where id=1 and name is null
//在执行第二条语句的时候
Update User set name='李四' where id=1 and name is null;

//这个时候,id=1的数据name已经修改成为了【张三】,在数据库中,这个时候第二条语句中,name is null就不成立,就会提示:影响行数为0
  这个时候EF的乐观锁就会抛出异常,提示并发修改失败,就需要用try cach来包裹异常,处理

 

 

 

 

 EF乐观锁的第二种实现方式

这种是属于第一种的延伸。扩展,解决多列值一起修改的并发控制

1、在数据库中新增一个timestanp类型,其实在C#代码中就是一个byte数组,一串二进制代码。这一个列是由数据库维护的。当你的这一行发生任何改变,对应的token令牌列的值就会发生改变,跟第一种实现方式对比来说,就实现了多列值的并发控制。

//实体中的token令牌字段

public byte[] RowVersion{get;set;}

 

 

 EF乐观和悲观锁的总结

 

 DbFirst,实体生成数据库

//建立实体对应的数据库模型 

public class Book { public int Id { get; set; } public string BookName { get; set; } public DateTime InsertTiem { get; set; } public byte[] RowVersion { get; set; } }
//建立对应的数据库表的配置文件,可以不要这个配置,也不影响,但是有这个文件更好。可以做一些特殊的操作,针对表
public class BookConifg : IEntityTypeConfiguration<Book> { public void Configure(EntityTypeBuilder<Book> builder) { builder.ToTable(name:"T_Books");
        builder.Property(x => x.RowVersion).IsRowVersion(); } }
//建立数据库对应的DBConetest
public
class MyDbContext:DbContext {
    //映射数据库对应的实体类
public DbSet<Book> Books { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { base.OnConfiguring(optionsBuilder);
      //数据库连接 optionsBuilder.UseSqlServer(
"Server=127.0.0.1;Database=TestDb;uid=**;Password=*******"); } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder);
      //这个是说用哪个程序集的实体来映射数据库表。this.GetType().Assenmbly就是获取本类的实现了
IEntityTypeConfiguration接口的表
      modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly); 
    }
  }

然后执行迁移命令

如果项目中有多个实现了DbContest接口的类,那么就需要指定对应的配置类,才可以实现迁移

Add-Migration  本地迁移的名称 -Context 指定的DbContext名称

然后执行才会修改数据库

Update-database

 

 

 

 

 

 

 

 

 

 

 

 

 

 


————————————————
版权声明:本文为CSDN博主「香煎三文鱼」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_39569480/article/details/110956156

posted @ 2022-06-16 22:27  仲夏不凉爽  阅读(332)  评论(0编辑  收藏  举报