十年河東,十年河西,莫欺少年窮
學無止境,精益求精
1、打開VS2019或VS2022創建一個webApi項目
添加引用
1.Microsoft.EntityFrameworkCore.SqlServer 2.Microsoft.EntityFrameworkCore.Design
本篇採用VS2019做演示
1.1、配置文件增加數據庫鏈接字符串
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*", "ConnectionStrings": { "swapDbContext": "Data Source=LAPTOP-84R6S0FB;Initial Catalog=swap;Integrated Security=True;MultipleActiveResultSets=true" } }
1.2、Startup.cs中ConfigureServices引入Sqlserver使用
public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddDbContext<swapDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("swapDbContext")), ServiceLifetime.Scoped); }
2、爲解決方案增加一個類庫,命名爲CoreDbContext
添加引用
1.Microsoft.EntityFrameworkCore.Relational 2.Microsoft.EntityFrameworkCore.Tools 3.Microsoft.EntityFrameworkCore.SqlServer
2.1、新建DbConfigs、DbDtos、文件夾及swapDbContext.cs類
2.2、在DbDtos文件夾創建一個簡單的實體
namespace CoreDbContext.DbDtos { public class book { public string uid { get; set; } public string bookName { get; set; } public bool IsDeleted { get; set; } } }
2.3、在DbConfigs文件夾中創建實體配置【指定主鍵,全局篩選器,字段長度、字段備註等】
internal class bookConfig : IEntityTypeConfiguration<book> { public void Configure(EntityTypeBuilder<book> builder) { builder.ToTable("T_books"); builder.HasKey(A => A.uid); builder.HasQueryFilter(A => A.IsDeleted == false); builder.Property(A => A.bookName).HasMaxLength(50).HasComment("書名"); } }
2.4、創建數據庫上下文
namespace CoreDbContext { /// <summary> /// add-Migration -Context 可以通過-Context 指定上下文,因此,項目中可以有多個DbCOntext,這樣就支持多個數據庫 /// </summary> public class swapDbContext : DbContext { public DbSet<book> books { get; set; } public swapDbContext(DbContextOptions<swapDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); //從當前程序集命名空間加載所有的IEntityTypeConfiguration modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly); } } /// <summary> /// 開發環境專用 用於add-Migration 時使用 /// </summary> public class swapDbContextFactory : IDesignTimeDbContextFactory<swapDbContext> { public swapDbContext CreateDbContext(string[] args) { var optionsBuilder = new DbContextOptionsBuilder<swapDbContext>(); optionsBuilder.UseSqlServer("Data Source=LAPTOP-84R6S0FB;Initial Catalog=swap;Integrated Security=True;MultipleActiveResultSets=true"); return new swapDbContext(optionsBuilder.Options); } } }
3、遷移數據庫
Add-Migration initDb
Update-DataBase
4、查看生成的數據庫及表
5、接合TransactionScope進行簡單事務測試
關於TransactonScope可參考:https://www.cnblogs.com/csdbfans/p/TransactionScope.html
5.1、驗證方法題內只有一個SaveChanges()時,執行的是事務
[HttpGet] public IActionResult TestBook() { book book = new book() { uid = Guid.NewGuid().ToString(), bookName = "平凡的世界", IsDeleted = false }; dbContext.books.Add(book); string name = ""; for (int i = 0; i < 20; i++) { name += "平凡的世界"; } book book2 = new book() { uid = Guid.NewGuid().ToString(), bookName = name, IsDeleted = false }; dbContext.books.Add(book2); dbContext.SaveChanges(); return Ok(); }
上述方法內只有一個SaveChanges,但書的名稱超出了最大值50,是否會引起事務回滾?
調試如下:
數據庫插入失敗
驗證結果:方法內只有一個SaveChanges時,EFCORE執行的是事務操作,因此當方法內只有一個SaveChanges時,就無須再使用TransactionScope了
5.2、驗證方法題內有多個SaveChanges()時,執行的不是事務
將上述方法增加一個saveChagnes
調試後,數據庫會增加一條記錄
驗證結果:方法內有多個SaveChanges時,EFCORE執行的是不事務操作,此時就需要接合使用TransactionScope了
5.3、接合TransactionScope來使用
[HttpGet] public IActionResult TestBook() { using (TransactionScope scope = new TransactionScope()) { book book = new book() { uid = Guid.NewGuid().ToString(), bookName = "平凡的世界", IsDeleted = false }; dbContext.books.Add(book); dbContext.SaveChanges(); book book1 = new book() { uid = Guid.NewGuid().ToString(), bookName = "鋼鐵是怎樣煉成的", IsDeleted = false }; dbContext.books.Add(book1); dbContext.SaveChanges(); string name = ""; for (int i = 0; i < 20; i++) { name += "平凡的世界"; } FormattableString sql = $"insert into [T_books] values(newid(),{name},0)"; dbContext.Database.ExecuteSqlInterpolated(sql); scope.Complete(); return Ok(); } }
注意,dbContext.Database.ExecuteSqlInterpolated()中的參數是帶有內插值的字符串,字符串中無需包含單引號
調試如下:
數據庫如下【之前插入的一條,我已刪除】:
驗證結果:在多個saveChanges時或者和原生SQL語句接合使用時,使用TransactionScope可以保證執行的是事務
5.4、異步操作的TransactionScope聲明【須使用參數:TransactionScopeAsyncFlowOption.Enabled】
[HttpGet] public async Task<IActionResult> TestBook() { using (TransactionScope scope = new TransactionScope( TransactionScopeAsyncFlowOption.Enabled)) { book book = new book() { uid = Guid.NewGuid().ToString(), bookName = "平凡的世界", IsDeleted = false }; dbContext.books.Add(book); await dbContext.SaveChangesAsync(); book book1 = new book() { uid = Guid.NewGuid().ToString(), bookName = "鋼鐵是怎樣煉成的", IsDeleted = false }; dbContext.books.Add(book1); await dbContext.SaveChangesAsync(); scope.Complete(); return Ok(); } }
6、多個DbContext上下文時怎麼做數據庫遷移
6.1、項目中新增TestDbContext
namespace CoreDbContext { /// <summary> /// add-Migration -Context 可以通過-Context 指定上下文,因此,項目中可以有多個DbCOntext,這樣就支持多個數據庫 /// </summary> public class TestDbContext : DbContext { public DbSet<book> books { get; set; } public TestDbContext(DbContextOptions<TestDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); //從當前程序集命名空間加載所有的IEntityTypeConfiguration modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly); } } /// <summary> /// 開發環境專用 用於add-Migration 時使用 /// </summary> public class TestDbContextFactory : IDesignTimeDbContextFactory<TestDbContext> { public TestDbContext CreateDbContext(string[] args) { var optionsBuilder = new DbContextOptionsBuilder<TestDbContext>(); optionsBuilder.UseSqlServer("Data Source=LAPTOP-84R6S0FB;Initial Catalog=TestDb;Integrated Security=True;MultipleActiveResultSets=true"); return new TestDbContext(optionsBuilder.Options); } } }
6.2、配置文件中新增鏈接字符串並在Startup.cs中註冊TestDbContext
public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddDbContext<swapDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("swapDbContext")), ServiceLifetime.Scoped); services.AddDbContext<TestDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("TestDbContext")), ServiceLifetime.Scoped); }
6.3、數據遷移
數據遷移時報錯,要求帶上 -Context 參數
因此,當項目中有多個DbContext時,我們在做數據庫遷移時需要指定context
Add-Migration addTestDb -context TestDbContext
Update-DataBase -context TestDbContext
6.4、遷移成功,查看數據庫
多個數據庫上下文就使得項目支持多數據庫鏈接,使用場景如連接備份數據庫、配置數據庫等
@天才臥龍的博科人