Asp.net Core Mvc EF- Migrations使用-生成資料庫
Asp.net Core Mvc EF- Migrations使用
2019-01-26 15:35糯米粥 閱讀(4210) 評論(0)編輯收藏
Migragtion的命令,左邊是手動命令,右邊是程式碼方式
首先來看命令方式:
建立一個mvc專案,預設已經集成了EF包
建立的專案包含了Microsoft.AspNetCore.Identity.EntityFramewordCore包,這將使用Entity Framework Core通過SQL Server來儲存身份識別的資料和表資訊。
新增Sql連線字串:
{ "Logging": { "LogLevel": { "Default": "Warning" } }, "AllowedHosts": "*", "ConnectionStrings": { "conn": "Data Source=pc;User ID=sa;Password=12;database=CoreDb;Connect Timeout=30;Encrypt=False;
TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False" } }
注意這個:ConnectionStrings是必須要這樣寫的,預設是根據這個名字讀取,後面會說
Net Core 身份 Identity 允許嚮應用中新增登陸功能。使用者可建立一個賬戶並進行登陸,登陸時可使用使用者名稱、密碼
Server資料庫儲存使用者名稱字、密碼和配置檔案資料。另外,你可使用其他已有的儲存空間儲存資料
建立ApplicationUser, ApplicationRole 分別繼承IdentityRole IdentityUser
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; namespace IdentityDemo.Models { public class ApplicationRole:IdentityRole { } }
using Microsoft.AspNetCore.Identity; namespace IdentityDemo.Models { public class ApplicationUser : IdentityUser { } }
建立上下文類:
using IdentityDemo.Models; using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; namespace IdentityDemo.Date { public class ApplicationDbContext : IdentityDbContext<ApplicationUser> { public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { } } }
ConfigureServices 中註冊服務
public void ConfigureServices(IServiceCollection services) { services.Configure<CookiePolicyOptions>(options => { // This lambda determines whether user consent for non-essential cookies is needed for a given request. options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.LoginPath = "/Login"; }); services.AddDbContext<ApplicationDbContext>(options => { //配置檔案前面必須是;ConnectionStrings //因為預設是:GetSection("ConnectionStrings")[name]. options.UseSqlServer(Configuration.GetConnectionString("conn")); //options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"])); }); services.AddIdentity<ApplicationUser, ApplicationRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders(); //配置密碼註冊方式 services.Configure<IdentityOptions>(options => { options.Password.RequireLowercase = false; options.Password.RequireNonAlphanumeric = false; options.Password.RequireUppercase = false; options.Password.RequiredLength = 1; }); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); }
我這裡用了Cookie驗證,所以應該新增中介軟體 app.UseAuthentication();
建立使用者:通過依賴注入: UserManager 和 SignInManager 依賴:Microsoft.AspNetCore.Identity;
private readonly UserManager<ApplicationUser> _userManager; private readonly SignInManager<ApplicationUser> _signinManager; public LoginController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signinManager) { _userManager = userManager; _signinManager = signinManager; }
註冊程式碼
[HttpPost] public async Task<IActionResult> Registe(LoginViewModel model) { var identityUser = new ApplicationUser { UserName = model.UserName, PasswordHash = model.PassWorld, NormalizedEmail = model.UserName }; var identityResult = await _userManager.CreateAsync(identityUser, model.PassWorld); if (identityResult.Succeeded) { return RedirectToAction("Index", "Home"); } return View(); }
註冊之前,我們先通過命令生成資料庫
命令依賴於:Microsoft.EntityFrameworkCore.Tools包,不過預設也有了
可以輸入dotnet ef migrations --help 看看幫助
輸入後命令:dotnet ef migrations add identity
專案中會生成一個Migrations的資料夾和檔案
然後更新資料庫:dotnet ef migrations update
可以看到生成了資料庫和表,但AspNetUsers表的組建ID預設是字串型別的,一連串GUID,待會會說改成常用的int型別
好了。現在註冊一個看看
看看預設的:
接下來我們修改預設的主鍵為int型別。只需要改成:IdentityUser<int> ,IdentityRole<int>
上下文改成:
因為是重新生成資料庫,需要刪除資料庫,並且把Migrations的檔案都刪除,或者直接刪除Migrations資料夾
可以執行命令刪除庫:dotnet ef database drop
否則EF會當作升級和降級處理,不會重新生成資料庫
然後重新migragins add ,update 註冊看看,已經是int型別了
然後給表升級,在使用者表新增一列 TrueName,首先看使用者名錶。預設是沒有該列的
我們在ApplicationUser類新增欄位
然後命令:dotnet ef migrations add AddTrueName //AddTrueName名字是任意取的
此時在Migrations資料夾生成了對呀的類
然後update,這裡的update只會找最新的migrations 這裡的最新的migrations就是20190126061435_identity
資料庫已經有了
比如我們在新增一個Address列,然後在還原到只有TrueName的狀態
現在Migrations有3個Migration
然後我們通過update回滾
dotnet ef database update 回滾的migration
我們這裡回滾到AddTrueName 那麼命令就是:dotnet ef database update AddTrueName
回滾之後。表也更新了
其實__EFMigrationsHistory表是儲存了當前所有的Migration
回滾前
回滾後
這裡有兩個AddTrueName是因為我add了兩次,可以不用管
主要是對比之前和之後,AddAddress沒有了
然後看:dotnet ef migrations script 生成指令碼
生成指令碼在螢幕中,還得拷貝出來,多不友好,看看--help,是可以指定路徑的
執行: dotnet ef migrations script -o d:\script\user.sql
開啟生成的檔案看看
dotnet ef migratoins remove 是移除最新的一個migration,remove一次就移除一次,
前提是該migration沒有update到database,如果細心你會發現,當你add migration時候,會提示,可以remove 移除
我們新增3個 migration 分別是 temp01,temp02,temp03
此時已經添加了3個測試的
記住,我這裡都沒有執行update的,所以在__EFMigrationsHistory也不會記錄。該表記錄的是已經update到database的migration
我們執行一次命令:dotnet ef migrations remove
因為temp03是最後新增的,所以先刪除,是不是像入棧出棧
在remove一次,按照上面說的,應該是移除temp02
就不一一測試了
來看看,如果update 後。能不能remove,上面已經還原到了TrueName
我們先升級到Address
執行命令:dotnet ef database update Addaddress
表字段和歷史紀錄也都有了
然後我們執行命令:dotnet ef migrations remove
這裡要注意一點,我們是加了Adress後,我為了測試,又加了temp01,02,03,上面測試只remove了03,02
如果你沒有remove01的話,現在remove是remove的01,注意下就好了
現在我們預設01,02,03都已經remove了。最新的肯定就是address了
好了,有點囉嗦。執行命令:dotnet ef migrations remove
info提示該migratin已經udate到database
通過dotnet ef migrations remove --help
可以看到有其他選項,有興趣的可以自行研究
上面都是手動執行命令,我們來看看在程式碼裡面怎麼做
在程式初始化的時候,新增一個預設管理員的賬號,例項程式碼如下
建立一個ApplicationDbContextSeed類,用於建立預設使用者
using IdentityDemo.Models; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; using System; using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.Logging; namespace IdentityDemo.Date { public class ApplicationDbContextSeed { private UserManager<ApplicationUser> _userManger; /// <summary> /// /// </summary> /// <param name="context">上下文</param> /// <param name="server">依賴注入的容器,這裡可以獲取依賴注入</param> /// <returns></returns> public async Task AsyncSpeed(ApplicationDbContext context, IServiceProvider server) { try { _userManger = server.GetRequiredService<UserManager<ApplicationUser>>(); var logger = server.GetRequiredService<ILogger<ApplicationDbContext>>(); logger.LogInformation("speed Init"); //如果沒有使用者,則建立一個 if (!_userManger.Users.Any()) { var defaultUser = new ApplicationUser { UserName = "Admin", dEmail = "[email protected]" }; var userResult = await _userManger.CreateAsync(defaultUser, "123456"); if(!userResult.Succeeded) { logger.LogError("建立失敗"); //logger.LogInformation("初始化使用者失敗"); userResult.Errors.ToList().ForEach(e => { logger.LogError(e.Description); }); } } } catch (Exception ex) { throw new Exception("初始化使用者失敗"); } } } }
新增一個對IWebHost擴充套件的類:
using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using System; namespace IdentityDemo.Date { public static class WebHostMigrationExtensions { public static IWebHost MigrationDbContext<TContext>(this IWebHost host, Action<TContext, IServiceProvider> sedder) where TContext : DbContext { using (var scope = host.Services.CreateScope()) { //拿到依賴注入容器 var servers = scope.ServiceProvider; //var logger = servers.GetRequiredService<ILogger<TContext>>(); var logger = servers.GetService<ILogger<TContext>>(); var context = servers.GetService<TContext>(); try { context.Database.Migrate(); sedder(context, servers); logger.LogInformation($"執行DbContex{typeof(TContext).Name}seed方法成功"); } catch (Exception ex) { logger.LogError(ex, $"執行DbContex{typeof(TContext).Name}seed方法失敗"); } } return host; } } }
這樣就可以在Program.cs的main方法中呼叫
因為方法是非同步方法,所以用Wait()方法改為同步的
然後刪除Migration中的所有檔案,重新add,可以 不update,因為程式碼會:context.Database.Migrate();
然後資料庫已經初始化了
通過var user = _userManager.FindByEmailAsync("[email protected]").Result;可以查詢使用者,
[HttpPost] public IActionResult Login(LoginViewModel model) { var user = _userManager.FindByEmailAsync(model.Email).Result; if (user!=null) { var claims = new List<Claim> { new Claim("name",model.UserName) }; var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); var cliamsPrincipal = new ClaimsPrincipal(claimsIdentity); HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, cliamsPrincipal); return RedirectToAction("Index", "Home"); } return RedirectToAction("Index"); }
本文主要講了magration的操作和identity身份的驗證
原始碼:https://github.com/byniqing/AspNetCore-identity
參考資料
https://docs.microsoft.com/en-us/aspnet/core/migration/proper-to-2x/?view=aspnetcore-2.2
https://www.cnblogs.com/jqdy/p/5941248.html
https://docs.microsoft.com/zh-cn/ef/core/miscellaneous/cli/dotnet#dotnet-ef-migrations-remove