Asp.net Core Mvc EF- Migrations使用


 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 = "cnblogs@163.com"
                    };
                    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("cnblogs@163.com").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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM