草庐IT

.Net -- EF Core

小蜗 2023-03-28 原文

1. EF Core简介
Entity Framework (EF) Core 是轻量化、可扩展、开源和跨平台版的常用 Entity Framework 数据访问技术。

EF Core 可用作对象关系映射程序 (O/RM),这可以实现以下两点:

使 .NET 开发人员能够使用 .NET 对象处理数据库。
无需再像通常那样编写大部分数据访问代码。
EF Core 支持多个数据库引擎,请参阅数据库提供程序了解详细信息。

Code First :先编写 C# 实体类,EF Core 会根据实体类之间的关系创建数据库;

Database First :先设计和创建数据库,EF Core 根据数据库的表结构生成 C# 实体类。

 DBFirst

1.点击“工具”->“NuGet包管理器”->“程序包管理器控制台”

分别安装以下几个包

Mysql 版本:

Install-Package MySql.Data.EntityFrameworkCore -Pre
Install-Package Pomelo.EntityFrameworkCore.MySql
Install-Package Microsoft.EntityFrameworkCore.Tools

Sql server 版本:

Install-Package Microsoft.EntityFrameworkCore
Install-Package Microsoft.EntityFrameworkCore.SqlServer
Install-Package Microsoft.EntityFrameworkCore.Tools

2.在程序包包管理器控制台 中执行以下语句生成 实体类   Scaffold-DbContext指令详情
–mysql 版本:输入如下指令,

Scaffold-DbContext "server=.;userid=tech5_kj;pwd=xxx;port=3306;database=tech5_kj;sslmode=none;" Pomelo.EntityFrameworkCore.MySql -OutputDir Models -Force

或者

Scaffold-DbContext "server=.;userid=tech5_kj;pwd=xxx;port=3306;database=tech5_kj;sslmode=none;" Pomelo.EntityFrameworkCore.MySql -OutputDir Models -UseDatabaseNames -Force

server:数据库地址,User Id:账号,Password:登录密码
如果是针对单表的更新,加一个-Tables 后面是要更新的表名

Scaffold-DbContext -Force "Server=****;User Id=root;Password=****;Database=****" -Provider "Pomelo.EntityFrameworkCore.MySql" -Tables "myTable"

–sql server 版本:

Scaffold-DbContext "Data Source=.;Initial Catalog=EFCore_dbfirst;User ID=sa;Password=sa.123" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -Force

或者

一般用这个就行!!!!
Scaffold-DbContext "Server=.;Database=EFCoreDemo;uid=sa;pwd=123" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models

通用的命令格式

Scaffold-DbContext "数据库连接字符串" EF组件名(Microsoft.EntityFrameworkCore.SqlServer/Pomelo.EntityFrameworkCore.MySql/等等) -OutputDir 输出文件夹名称

参数说明:

-OutputDir *** 实体文件所存放的文件目录
-ContextDir *** DbContext文件存放的目录
-Context *** DbContext文件名
-Schemas *** 需要生成实体数据的数据表所在的模式
-Tables *** 需要生成实体数据的数据表的集合
-DataAnnotations
-UseDatabaseNames 直接使用数据库中的表名和列名(某些版本不支持)
-Force 强制执行,重写已经存在的实体文件

 运行成功后,生成如下实体类

 

 context中配置数据库连接时,使用明文产生此警告,可改为使用配置文档

 

 添加配置文档appsettings.json

{
  "ConnectionStrings": {
    "NpgsqlDbConn_DBFirst": "Server=127.0.0.1;Port=5432;Database=EFCoreDB;User Id=postgres;Password=1;",
    "MysqlDbConn_CodeFirst": "Server=127.0.0.1;Port=3306;Database=EFCoreCode;User Id=root;Password=hirosedb;"
  }
} 

 调用

nuget 引用以下三个包:

Microsoft.Extensions.Configuration
Microsoft.Extensions.Configuration.FileExtensions
Microsoft.Extensions.Configuration.Json
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {
                IConfiguration config = new ConfigurationBuilder()
                     .SetBasePath(Directory.GetCurrentDirectory())
                     .AddJsonFile("appsettings.json")
                     .Build();
                string ConnectStr = config.GetConnectionString("NpgsqlDbConn_DBFirst");
                optionsBuilder.UseNpgsql(ConnectStr);
            }
        } 

   CodeFirst

CodeFirst使用Mysql,Nuget安装如下包

 

 

 新建实体类:Book、Comment,使用特性实体与数据库对应

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
 
namespace EFCore_CodeFirst
{
    [Table("Book")]   //表名
    public class Book
    {
        [Key]    //主键
        [Column("Id")]  //列名
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]  //主键自增
        public int Id { get; set; }
        [Column("Title")]
        public string? Title { get; set; }
        [Column("Price")]
        public double? Price { get; set; }
        [Column("PubTime")]
        public DateTime? PubTime { get; set; }=DateTime.Now;
        [Column("AuthorName")]
        public string? AuthorName { get; set; }
    }
} 
[Table("Comment")]
    public class Comment
    {
        [Key]
        [Column("Id")]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
        [Column("Title")]
        public string? Title { get; set; }
        [Column("CreatedDate")]
        public DateTime CreatedDate { get; set; }=DateTime.Now;
        [Column("CommentStr")]
        public string? CommentStr { get; set; }
    } 

创建context类,继承DbContext

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
 
namespace EFCore_CodeFirst
{
    public class CodeFContext : DbContext
    {
        //定义实体  EFcore默认追踪
        public DbSet<Book> Books { get; set; } = null!;
        public DbSet<Comment> Comments { get; set; } = null!;
        private string ConnectStr=null!;
 
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {
                IConfiguration config = new ConfigurationBuilder()
                     .SetBasePath(Directory.GetCurrentDirectory())
                     .AddJsonFile("appsettings.json")
                     .Build();
                ConnectStr = config.GetConnectionString("MysqlDbConn_CodeFirst");
                optionsBuilder.UseMySql(ConnectStr, ServerVersion.AutoDetect(ConnectStr));
            }
        }
 
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
        }
    }
} 

由实体生成数据库,将EFCore_CodeFirst设为启动项目,调用指令add-migration "变量";

 

 

 会生成如下文件

 

 

 调用指令Update-Database ,更新数据库

 

 

 使用Navicat查看数据库,生成成功

 

 

 

 EF Core -- 增删改查

先new一个context实例,通过绑定跟踪的DbSet实体,实现数据操作

private CodeFContext codeFContext= new CodeFContext();

 查询

private List<Book> _books;
 
        public List<Book> Books
        {
            get => _books; 
            set => SetProperty  (ref _books, value);
        }
//查询Book表所有数据
Books = codeFContext.Books.ToList();
//条件查询,linq操作
Books = codeFContext.Books.Where(x => x.Id > 3).ToList(); 

插入

private async void InsertData()
        {
            var books=new List<Book>() { 
                new Book() { Title ="追风筝的人"},
                new Book() { Title ="霍乱时期的爱情"}
            };
            //修改DbSet
            codeFContext.Books.AddRange(books);
            //再save更改
            await codeFContext.SaveChangesAsync();
        } 

更新

private async void UpdateData()
        {
            //需要先查询
            var books = codeFContext.Books.Where(x => x.Title == "追风筝的人");
            //再对查询到的数据进行修改
            foreach (var item in books)
            {
                item.Title = "放学后";
            }
            //再save更改
            await codeFContext.SaveChangesAsync();
 
        } 

删除

private async void DeleteData()
        {
            //先Linq查询
            var books= codeFContext.Books.Where(x => x.Id>5);
            //从实体中删除数据
            codeFContext.Books.RemoveRange(books);
            //再save更改
            await codeFContext.SaveChangesAsync();
        } 

EF Core -- 批量更新

EF 目前不提供用于执行批量更新的 API.

 使用EFCore.BulkExtensions操作Postgresql

 Bulk相关(一条操作一个事务,均是传入实体)

//查询
List<Student> students =new List<Student>();
 await dbFContext.BulkReadAsync(students);
//插入
var students = new List<Student>(){
                new Student() {Id=1, Name = "AA" ,StuNum="2010"},
                new Student() {Id=2, Name = "BB" ,StuNum="2011"},
                new Student() {Id=3, Name = "CC",StuNum="2012" }};
            await dbFContext.BulkInsertAsync(students);
//删除
var stus = dbFContext.Students;
            await dbFContext.BulkDeleteAsync(stus.ToList());
//更新
var stus = dbFContext.Students.ToList();
            foreach (var item in stus)
            {
                item.Name += "QQQ";
            }
            await dbFContext.BulkUpdateAsync(stus); 

Batch相关(按条件)

//删除
await dbFContext.Students.Where(x=>x.Name=="BB").BatchDeleteAsync();
//更新(改成新数据)
await dbFContext.Students.Where(x => x.StuNum == "2222").BatchUpdateAsync(new Student() {StuNum="2233" });
//更新(基于原数据)
await dbFContext.Students.Where(x => x.StuNum == "2233").BatchUpdateAsync(x=>new Student() { StuNum =x.StuNum+ "444" }); 

事务

//Bulk相关(一条操作一个事务,均是传入实体)
        //直接使用这些操作时,每个操作都是独立的事务,并且会自动提交。
        //如果我们需要在单个过程中执行多个操作,则应使用显式事务
        public async void TransactionTest()
        {
            using (var transaction= dbFContext.Database.BeginTransaction())
            {
                try
                {
                    var students = new List<Student>(){
                     new Student() {Id=6, Name = "DD" ,StuNum="2044"},
                     new Student() {Id=7, Name = "EE" ,StuNum="2055"}};
                    await dbFContext.BulkInsertAsync(students);
                    await dbFContext.Students.Where(x => x.StuNum == "2044").BatchUpdateAsync(new Student() { Name = "DDEEF" });
                    transaction.Commit();
                }
                catch (Exception ex )
                {
                    //using包裹不需要手写rollback,报错会自动回滚
                    Console.WriteLine(ex.Message);
                }
                
            }
        } 

使用 Zack.EFCore.Batch.MySQL.Pomelo_NET6 操作Mysql

//添加配置
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {
                optionsBuilder.UseBatchEF_MySQLPomelo();
            }
        }
 
 
//批量删除,
await codeFContext.DeleteRangeAsync<Book>(x=>x.Id>5);
//批量更新,条件,设置更新的列和值,执行
            await codeFContext.BatchUpdate<Book>()
                .Where(x => x.Title == "放学后")
                .Set(x=>x.Title,x=>x.Title+"Test")
                .Set(x=>x.Price,x=>20)
                .ExecuteAsync();
//批量删除和批量更新都支持通过Take()、Skip()来实现部分删除和部分更新
// Take(3) 代表选取3个 ,如果满足条件的不足3个 那就有几个选几个 可以一个都没有,超过的话只选顺序前 3 个
await codeFContext.Books.Where(x=>x.Id>5).Take(3).DeleteRangeAsync(codeFContext);
//Skip(3) 代表跳过3个 ,如果满足条件的不足3个 那就有几个选几个 跳过几个,超过的话只跳过顺序的前 3 个
await codeFContext.BatchUpdate<Book>()
                .Where(x => x.Title == "放学后")
                .Set(x => x.Title, x => x.Title + "Test")
                .Set(x => x.Price, x => 20)
                .Skip(3)
                .ExecuteAsync();
//批量插入
var books=new List<Book>() { 
                new Book() { Title ="追风筝的人"},
                new Book() { Title ="霍乱时期的爱情"}
            };
            await codeFContext.BulkInsertAsync(books); 

 

相关链接: https://blog.csdn.net/a549742320/article/details/124094237

                  https://www.cnblogs.com/wl-blog/p/16500751.html

 

有关.Net -- EF Core的更多相关文章

  1. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  2. ruby - 如何模拟 Net::HTTP::Post? - 2

    是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou

  3. ruby - Net::HTTP 获取源代码和状态 - 2

    我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

  4. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  5. .net - .NET 将如何影响 Python 和 Ruby 应用程序? - 2

    我很好奇.NET将如何影响Python和Ruby应用程序。用IronPython/IronRuby编写的应用程序是否会非常特定于.NET环境,以至于它们实际上将变得特定于平台?如果他们不使用任何.NET功能,那么IronPython/IronRuby相对于非.NET同类产品的优势是什么? 最佳答案 我不能说任何关于IronRuby的东西,但是大多数Python实现(如IronPython、Jython和PyPy)都试图尽可能忠实于CPython实现。不过,IronPython正在迅速成为这方面的佼佼者之一,并且在PlanetPyth

  6. ruby - 如何使用 Ruby HTTP::Net 处理 404 错误? - 2

    我正在尝试解析网页,但有时会收到404错误。这是我用来获取网页的代码:result=Net::HTTP::getURI.parse(URI.escape(url))如何测试result是否为404错误代码? 最佳答案 像这样重写你的代码:uri=URI.parse(url)result=Net::HTTP.start(uri.host,uri.port){|http|http.get(uri.path)}putsresult.codeputsresult.body这将打印状态码和正文。

  7. .net - 是否有 Ruby .NET 编译器? - 2

    是否有适用于Ruby语言的.NETFramework编译器?我听说过DLR(动态语言运行时),这是否将使Ruby能够用于.NET开发? 最佳答案 IronRuby是Microsoft支持的项目,建立在动态语言运行时之上。 关于.net-是否有Ruby.NET编译器?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/199638/

  8. ruby - 使用 ruby​​ gem net-ssh-multi 同时在多个服务器上执行 sudo 命令 - 2

    在previousquestion中我想出了如何在多个服务器上启动经过密码验证的sshsession来运行单个命令。现在我需要能够执行“sudo”命令。问题是,net-ssh-multi没有分配sudo需要运行的伪终端(pty),导致以下错误:[127.0.0.1:stderr]sudo:sorry,youmusthaveattytorunsudo根据documentation,可以通过调用channel对象的方法来分配伪终端,但是,以下代码不起作用:它会生成上面的“notty”错误:require'net/ssh'require'net/ssh/multi'Net::SSH::Mul

  9. (附源码)vue3.0+.NET6实现聊天室(实时聊天SignalR) - 2

    参考文章搭建文章gitte源码在线体验可以注册两个号来测试演示图:一.整体介绍  介绍SignalR一种通讯模型Hub(中心模型,或者叫集线器模型),调用这个模型写好的方法,去发送消息。  内容有:    ①:Hub模型的方法介绍    ②:服务器端代码介绍    ③:前端vue3安装并调用后端方法    ④:聊天室样例整体流程:1、进入网站->调用连接SignalR的方法2、与好友发送消息->调用SignalR的自定义方法 前端通过,signalR内置方法.invoke()  去请求接口3、监听接受方法(渲染消息)通过new signalR.HubConnectionBuilder().on

  10. ruby - Net::SSH sudo 命令在输入密码后挂起 - 2

    我一直在尝试使用Thor编写一个小型库,以帮助我快速创建新项目和站点。我写了这个小方法:defssh(cmd)Net::SSH.start(server_ip,user,:port=>port)do|session|session.execcmdendend只是协助我在需要时在远程服务器上运行快速命令。问题是当我需要在远程端的sudo下运行命令时,脚本似乎卡在我身上。例如当执行这个...ssh("sudocp#{file_from_path}#{file_to_path}")脚本会提示我输入密码[sudo]passwordforuser:但是在输入之后整个事情就挂起。有人会碰巧知道它为

随机推荐