日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > asp.net >内容正文

asp.net

.NET EFCore之增删改查

發(fā)布時(shí)間:2024/9/3 asp.net 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .NET EFCore之增删改查 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

  1. 連接數(shù)據(jù)庫(kù)

  通過(guò)依賴(lài)注入配置應(yīng)用程序,通過(guò)startup類(lèi)的ConfigureService方法中的AddDbContext將EFCore添加到依賴(lài)注入容器

  public void ConfigureServices(IServiceCollection services)

  {

  services.AddControllers();

  services.AddDbContext(

  options => options.UseMySql(Configuration["DbConfig:Mysql:ConnectionString"]);

  }

  將名為 OpenDbContext的 DbContext 子類(lèi)注冊(cè)到依賴(lài)注入容器的Scope生命周期。上下文配置為使用MySQL數(shù)據(jù)庫(kù)提供程序,并從配置中讀取數(shù)據(jù)庫(kù)連接字符串。

  OpenDbContext類(lèi)必須公開(kāi)具有 DbContextOptions參數(shù)的公共構(gòu)造函數(shù)。這是將 AddDbContext 的上下文配置傳遞到 DbContext 的方式。

  public class OpenDbContext : DbContext

  {

  public OpenDbContext(DbContextOptions options) : base(options)

  {

  }

  public DbSet?Users { get; set; }

  public DbSet?Scores { get; set; }

  protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)

  {

  //另一種配置連接數(shù)據(jù)庫(kù)的方式

  //optionsBuilder.UseMySql("連接數(shù)據(jù)庫(kù)", ServerVersion.AutoDetect("連接數(shù)據(jù)庫(kù)字符串"));

  //顯示敏感數(shù)據(jù)日志

  optionsBuilder.EnableSensitiveDataLogging(true);

  }

  protected override void OnModelCreating(ModelBuilder modelBuilder)

  {

  //屬性配置

  //modelBuilder.Entity()perty(t => t.Account).IsRequired().HasMaxLength(20).HasComment("帳號(hào)");

  //種子數(shù)據(jù)設(shè)置

  //modelBuilder.Entity().HasData(new User { Account="種子"});

  //批量添加etc的操作

  modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());

  base.OnModelCreating(modelBuilder);

  }

  }

  然后將OpenDbContext通過(guò)構(gòu)造函數(shù)注入的方式注入到應(yīng)用程序的控制器或者其他服務(wù)中使用。

  關(guān)于連接數(shù)據(jù)庫(kù)可以參考另一個(gè)文章:.Net之生成數(shù)據(jù)庫(kù)全流程

  2. 操作數(shù)據(jù)庫(kù)

  context.Database.EnsureDeleted();//刪除數(shù)據(jù)庫(kù),如果存在,如果沒(méi)有權(quán)限,則引發(fā)異常

  context.Database.EnsureCreated();//如果數(shù)據(jù)庫(kù)不存在,創(chuàng)建數(shù)據(jù)庫(kù)并初始化數(shù)據(jù)庫(kù)架構(gòu),如果存在任何表,則不會(huì)初始化架構(gòu)

  context.Database.Migrate();//根據(jù)遷移文件,遷移數(shù)據(jù)庫(kù)

  3. 查詢(xún)操作3.1 基礎(chǔ)查詢(xún)

  db.Set().ToList();

  //查詢(xún)表達(dá)式

  var account = (from u in _context.Users

  where u.Id == id

  select u.Account

  ).ToList();

  //查詢(xún)單個(gè)

  _context.Movie.FirstOrDefaultAsync(m => m.ID == id);

  _context.Movie.FindAsync(id);

  //查詢(xún)指定列

  _context.Set().AsNoTracking().Where(t=>t.Id=="11").Select(t => new { t.Account, t.PassWord }).FirstOrDefaultAsync();

  // 預(yù)先加載查詢(xún)

  var blogs = context.Blogs.Include(blog => blog.Posts).ToList();

  // 包含多個(gè)層級(jí)的查詢(xún)

  var blogs = context.Blogs.Include(blog => blog.Posts).ThenInclude(post => post.Author).ToList();

  SingleOrDefaultAsync 與FirstOrDefaultAsync

  如果有多個(gè)實(shí)體符合篩選部分, SingleOrDefaultAsync 將引發(fā)異常。

  如果有多個(gè)實(shí)體符合篩選部分, FirstOrDefaultAsync 不引發(fā)異常。

  FindAsync

  在大部分基架代碼中,FindAsync 可用于替代 FirstOrDefaultAsync ,查找具有主鍵 (PK) 的實(shí)體。如果具有 PK 的實(shí)體正在由上下文跟蹤,會(huì)返回該實(shí)體且不向 DB 發(fā)出請(qǐng)求。

  3.2 跟蹤和非跟蹤查詢(xún)

  跟蹤行為決定了EFCore是否將有些實(shí)體的信息保存在其更改更跟蹤器中。如果已跟蹤某個(gè)實(shí)體,則該實(shí)體中檢測(cè)到的任何更改都會(huì)在SaveChanges()時(shí)候保存到數(shù)據(jù)庫(kù),

  不跟蹤沒(méi)有主鍵的實(shí)體類(lèi)型。

  # 跟蹤查詢(xún)

  _context.Set().ToListAsync();

  # 非跟蹤查詢(xún)

  _context.Set().AsNoTracking().ToListAsync();

  默認(rèn)是跟蹤查詢(xún)

  3.3 條件查詢(xún)3.3.1 不支持異步方案

  Func?express = x => true;

  if (!string.IsNullOrWhiteSpace(dto.Data))

  {

  express = x => xle == dto.Data;

  }

  string userid = "";

  if (!string.IsNullOrWhiteSpace(userid))

  {

  express = x => x.UserId == userid;

  }

  var bbb = _dbContext.Set().Where(express).FirstOrDefault();

  3.3.2 支持異步方案

  Expression> express = x => true;

  if (!string.IsNullOrWhiteSpace(dto.Data))

  {

  express = x => xle == dto.Data;

  }

  var bbb = await _dbContext.Set().Where(express).ToListAsync();

  3.4 原生SQL查詢(xún)

  可使用 FromSqlRaw 擴(kuò)展方法基于原始 SQL 查詢(xún)開(kāi)始 LINQ 查詢(xún)。FromSqlRaw 只能在直接位于 DbSet<> 上的查詢(xún)根上使用。

  3.4.1 基本原生SQL查詢(xún)

  var blogs = context.Blogs

  .FromSqlRaw("select * from user")

  .ToList();

  // 執(zhí)行存儲(chǔ)過(guò)程

  var blogs = context.Blogs

  .FromSqlRaw("EXECUTE dbo.GetMostPopularBlogs")

  .ToList();

  2.x里面使用FromSql,在3.x里面使用FromSqlRow方法

  3.4.2 參數(shù)化查詢(xún)3.4.2.1 SQL注入

  首先我們編寫(xiě)一個(gè)簡(jiǎn)單的SQL注入示例,比如就注入我們根據(jù)ID查詢(xún)的語(yǔ)句,輸入ID為:ididid' or '1'='1

  var strSql = string.Format("select * from user where Id='{0}'", "ididid' or '1'='1");

  var query = await _context.Set().FromSqlRaw(strSql).ToListAsync();

  Console.WriteLine(JsonConvert.SerializeObject(query));

  生成語(yǔ)句

  select * from user where Id='ididid' or '1'='1'

  [{"Account":"張三","PassWord":"123456","CreateTime":"2021-05-20T22:53:44.778101","IsValid":false,"Id":"1395392302788120576"},{"Account":"李四","PassWord":"123456","CreateTime":"2021-05-20T22:53:44.849376","IsValid":false,"Id":"1395392303090110464"},{"Account":"王五","PassWord":"123456","CreateTime":"2021-05-20T22:53:44.849425","IsValid":false,"Id":"1395392303090110467"}]

  3.4.2.2 FromSqlRaw參數(shù)化

  通過(guò)參數(shù)化查詢(xún),防止SQL注入問(wèn)題

  //sql語(yǔ)句參數(shù)化查詢(xún),防止SQL注入

  var strSql = "select * from user where Id=@id";

  var parameter = new MySqlParameter[] {

  new MySqlParameter("@id","1395392302788120576"),

  };

  var query = await _context.Set().FromSqlRaw(strSql, parameter).ToListAsync();

  或者

  var strSql = "select * from user where Id={0}";

  var query = await _context.Set().FromSqlRaw(strSql, "1395392302788120576").ToListAsync();

  Console.WriteLine(JsonConvert.SerializeObject(query));

  // 生成SQL

  select * from user where Id=@p0

  [{"Account":"張三","PassWord":"123456","CreateTime":"2021-05-20T22:53:44.778101","IsValid":false,"Id":"1395392302788120576"}]

  通過(guò)占位符形式提供額外的參數(shù),看上去類(lèi)似于String.Format語(yǔ)法,但是提供的值包裝在DbParameter中。可以防止SQL注入

  3.4.2.3 FromSqlInterpolated參數(shù)化

  FromSqlInterpolated 類(lèi)似于 FromSqlRaw,但你可以借助它使用字符串內(nèi)插語(yǔ)法。與 FromSqlRaw 一樣,FromSqlInterpolated 只能在查詢(xún)根上使用,并且都可以防止SQL注入。

  var query = await _context.Set().FromSqlInterpolated($"select * from user where Id={"1395392302788120576"}").ToListAsync();

  Console.WriteLine(JsonConvert.SerializeObject(query));

  生成SQL

  select * from user where Id=@p0

  [{"Account":"張三","PassWord":"123456","CreateTime":"2021-05-20T22:53:44.778101","IsValid":false,"Id":"1395392302788120576"}]

  3.4.3 限制SQL查詢(xún)必須返回實(shí)體類(lèi)型的所有屬性的數(shù)據(jù)。結(jié)果集中的列明必須與屬性映射到的列名稱(chēng)匹配。SQL查詢(xún)不能包含關(guān)聯(lián)數(shù)據(jù), 但是,在許多情況下你可以在查詢(xún)后面緊跟著使用 Include 方法以返回關(guān)聯(lián)數(shù)據(jù)(請(qǐng)參閱包含關(guān)聯(lián)數(shù)據(jù))。

  參考文檔:docs.microsoft/zh-cn/ef/core/querying/raw-sql

  3.5 復(fù)雜查詢(xún)

  數(shù)據(jù)如下:

  用戶(hù)表(user)

  

  image.png

  用戶(hù)成績(jī)表(score)

  

  image.png

  描述:包含三個(gè)用戶(hù),其中兩個(gè)用戶(hù)在成績(jī)表都有語(yǔ)文和數(shù)學(xué)的數(shù)據(jù)。

  3.5.1 內(nèi)連接

  內(nèi)連接:分為隱式內(nèi)連接和顯式內(nèi)連接(寫(xiě)法不同,結(jié)果相同)

  3.5.1.1 Linq查詢(xún)表達(dá)式顯式內(nèi)連接:join-in-on拼接

  var list = (from u in _context.Users

  join sc in _context.Scores on u.Id equals sc.UserId

  where sc.CourseName == "語(yǔ)文"

  select new

  {

  u.Account,

  u.PassWord,

  sc.CourseName,

  sc.Grade

  }).ToList();

  Console.WriteLine(JsonConvert.SerializeObject(list));

  記得引用:System.Linq 否則提示:未找到源類(lèi)型“DbSet”的查詢(xún)模式的實(shí)現(xiàn),未找到j(luò)oin

  生成SQL

  SELECT `u`.`Account`, `u`.`PassWord`, `s`.`CourseName`, `s`.`Grade`

  FROM `user` AS `u`

  INNER JOIN `score` AS `s` ON `u`.`Id` = `s`.`UserId`

  WHERE `s`.`CourseName` = '語(yǔ)文'

  結(jié)果

  

  image.png

  隱式內(nèi)連接:多個(gè)from并聯(lián)拼接

  var list = (from u in _context.Users

  from sc in _context.Scores

  where u.Id == sc.UserId && sc.CourseName == "語(yǔ)文"

  select new

  {

  u.Account,

  u.PassWord,

  sc.CourseName,

  sc.Grade

  }).ToList();

  Console.WriteLine(JsonConvert.SerializeObject(list));

  生成SQL

  SELECT `u`.`Account`, `u`.`PassWord`, `s`.`CourseName`, `s`.`Grade`

  FROM `user` AS `u`

  CROSS JOIN `score` AS `s`

  WHERE (`u`.`Id` = `s`.`UserId`) AND (`s`.`CourseName` = '語(yǔ)文')

  結(jié)果

  

  image.png

  3.5.1.2 Linq標(biāo)準(zhǔn)查詢(xún)運(yùn)算符

  var list = _context.Users.Where(t => t.Account != null)

  .Join(_context.Scores.Where(sc => sc.CourseName == "語(yǔ)文"), u => u.Id, sc => sc.UserId, (u, sc) => new

  {

  u.Account,

  u.PassWord,

  sc.CourseName,

  sc.Grade

  }).ToList();

  Console.WriteLine(JsonConvert.SerializeObject(list));

  生成SQL

  # 不加查詢(xún)課程

  SELECT `u`.`Account`, `u`.`PassWord`, `s`.`CourseName`, `s`.`Grade`

  FROM `user` AS `u`

  INNER JOIN `score` AS `s` ON `u`.`Id` = `s`.`UserId`

  # 查詢(xún)課程

  SELECT `u`.`Account`, `u`.`PassWord`, `t`.`CourseName`, `t`.`Grade`

  FROM `user` AS `u`

  INNER JOIN (

  SELECT `s`.`CourseName`, `s`.`Grade`, `s`.`UserId`

  FROM `score` AS `s`

  WHERE `s`.`CourseName` = '語(yǔ)文'

  ) AS `t` ON `u`.`Id` = `t`.`UserId`

  結(jié)果

  

  image.png

  3.5.2 外連接

  外連接join后必須有into,然后可以加上XX.DefaultIfEmpty(),表示對(duì)于引用類(lèi)型將返回null,而對(duì)于值類(lèi)型則返回0。對(duì)于結(jié)構(gòu)體類(lèi)型,則會(huì)根據(jù)其成員類(lèi)型將它們相應(yīng)地初始化為null(引用類(lèi)型)或0(值類(lèi)型),

  如果僅需要統(tǒng)計(jì)右表的個(gè)數(shù)或者其它屬性,可以省略XX.DefaultIfEmpty, 但如果需要點(diǎn)出來(lái)右表的字段,則不能省。

  3.5.2.1 linq實(shí)現(xiàn)

  查詢(xún)所有用戶(hù)對(duì)應(yīng)的班級(jí),因?yàn)橛脩?hù)和成績(jī)一對(duì)多,所以會(huì)出現(xiàn)多條數(shù)據(jù)

  var list = (from u in _context.Users

  join sc in _context.Scores on u.Id equals sc.UserId

  into ulist

  from sco in ulist.DefaultIfEmpty()

  where u.Account != null //這個(gè)條件只是展示如何添加條件

  select new

  {

  UserId = u.Id,

  Account = u.Account,

  sco.CourseName

  }).ToList();

  Console.WriteLine(JsonConvert.SerializeObject(list));

  生成SQL

  SELECT `u`.`Id` AS `UserId`, `u`.`Account`, `s`.`CourseName`

  FROM `user` AS `u`

  LEFT JOIN `score` AS `s` ON `u`.`Id` = `s`.`UserId`

  結(jié)果

  

  image.png

  如果要查詢(xún)成績(jī),應(yīng)該這么寫(xiě),上面那個(gè)寫(xiě)法會(huì)直接報(bào)錯(cuò), Nullable object must have a value

  

  image.png

  3.5.3 GroupJoin

  GroupJoin操作符常應(yīng)用于返回“主鍵對(duì)象-外鍵對(duì)象集合”形式的查詢(xún),例如“用戶(hù)信息-此用戶(hù)下所有科目成績(jī)”

  var list = _context.Users.Where(t => t.Account != null)

  Join(_context.Scores, u => u.Id, sc => sc.UserId, (u, sc) => new

  {

  u.Account,

  u.PassWord,

  Scores = sc

  }).ToList();

  Console.WriteLine(JsonConvert.SerializeObject(list));

  該代碼會(huì)提示錯(cuò)誤,原因如:docs.microsoft/zh-cn/ef/core/querying/client-eval

  3.5.4 GrouBy

  分組操作 根據(jù)用戶(hù)分組,求科目數(shù)

  var list = (from sc in _context.Scores

  group sc by sc.UserId

  into g

  select new

  {

  g.Key,

  Count = g.Count()

  }).ToList();

  Console.WriteLine(JsonConvert.SerializeObject(list));

  var list2 = _context.ScoresBy(sc => sc.UserId).Select(t => new

  {

  t.Key,

  Count = t.Count()

  }).ToList();

  Console.WriteLine(JsonConvert.SerializeObject(list2));

  生成SQL

  info: Microsoft.EntityFrameworkCore.Databasemand[20101]

  Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30']

  SELECT `s`.`UserId` AS `Key`, COUNT(*) AS `Count`

  FROM `score` AS `s`

  GROUP BY `s`.`UserId`

  [{"Key":"1395392302788120576","Count":2},{"Key":"1395392303090110464","Count":2}]

  info: Microsoft.EntityFrameworkCore.Databasemand[20101]

  Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30']

  SELECT `s`.`UserId` AS `Key`, COUNT(*) AS `Count`

  FROM `score` AS `s`

  GROUP BY `s`.`UserId`

  [{"Key":"1395392302788120576","Count":2},{"Key":"1395392303090110464","Count":2}]

  4. 添加4.1 基礎(chǔ)添加

  _context.Movie.Add(movie);

  // or

  await _context.Movie.AddRangeAsync(movies)

  await _context.SaveChangesAsync();

  4.2 已經(jīng)設(shè)置自增鍵的插入

  先關(guān)閉自增然后插入數(shù)據(jù)后再開(kāi)啟自增

  db.Database.OpenConnection();

  db.Database.ExecuteSqlCommand("SET IDENTITY_INSERT [T_RoleInfor] ON");

  var r2 = new T_RoleInfor()

  {

  id = 123,

  roleName = "管理員",

  roleDescription = "我是管理員"

  };

  db.Add(r2);

  int count2 = db.SaveChanges();

  db.Database.ExecuteSqlCommand("SET ID ENTITY_INSERT [T_RoleInfor] OFF");

  4.3 通過(guò)SQL添加

  var strSql2 = "INSERT INTO `userinfo`(`Id`, `Account`, `PassWord`) VALUES (@id, @account, @password);";

  var parameter2 = new MySqlParameter[] {

  new MySqlParameter("@id","22"),

  new MySqlParameter("@account","2222"),

  new MySqlParameter("@password","22222")

  };

  var flg = db.Database.ExecuteSqlRaw(strSql2, parameter2);

  // 調(diào)用存儲(chǔ)過(guò)程

  int n = db.Database.ExecuteSqlCommand("DoSome @id", para);//參數(shù)化查詢(xún)

  2.x使用ExecuteSqlCommand,3.x使用ExecuteSqlRaw方法

  5. 修改

  var movie = await _context.Movie.FirstOrDefaultAsync(m => m.ID == id);

  movie.Name="李思";

  await _context.SaveChangesAsync();

  6. 刪除

  var movie = await _context.Movie.FirstOrDefaultAsync(m => m.ID == id);

  _context.Movie.Remove(movie);

  await _context.SaveChangesAsync();

總結(jié)

以上是生活随笔為你收集整理的.NET EFCore之增删改查的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。