diff --git a/Docs/学习总结.ipynb b/Docs/学习总结.ipynb index e73b1f3..c8f0e0b 100644 --- a/Docs/学习总结.ipynb +++ b/Docs/学习总结.ipynb @@ -19,7 +19,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": { "dotnet_interactive": { "language": "csharp" @@ -31,7 +31,17 @@ "languageId": "polyglot-notebook" } }, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "<div><div><strong>Restore sources</strong><ul><li><span>https://api.nuget.org/v3/index.json</span></li></ul></div><div></div><div><strong>Installed Packages</strong><ul><li><span>Microsoft.EntityFrameworkCore, 7.0.5</span></li><li><span>Microsoft.EntityFrameworkCore.InMemory, 7.0.5</span></li><li><span>Microsoft.EntityFrameworkCore.Sqlite, 7.0.5</span></li><li><span>Microsoft.EntityFrameworkCore.SqlServer, 7.0.5</span></li></ul></div></div>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "//设置包源\n", "#i \"https://api.nuget.org/v3/index.json\"\n", @@ -50,6 +60,104 @@ "source": [ "## DbContext" ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + }, + "vscode": { + "languageId": "polyglot-notebook" + } + }, + "outputs": [ + { + "data": { + "text/html": [ + "<table><thead><tr><th><i>index</i></th><th>value</th></tr></thead><tbody><tr><td>0</td><td><details class=\"dni-treeview\"><summary><span class=\"dni-code-hint\"><code>Submission#6+Account</code></span></summary><div><table><thead><tr></tr></thead><tbody><tr><td>Id</td><td><div class=\"dni-plaintext\"><pre>1</pre></div></td></tr><tr><td>Code</td><td>001</td></tr><tr><td>Name</td><td>zhangsan</td></tr><tr><td>Pwd</td><td>123456</td></tr><tr><td>Age</td><td><div class=\"dni-plaintext\"><pre>25</pre></div></td></tr><tr><td>State</td><td><div class=\"dni-plaintext\"><pre>0</pre></div></td></tr></tbody></table></div></details></td></tr><tr><td>1</td><td><details class=\"dni-treeview\"><summary><span class=\"dni-code-hint\"><code>Submission#6+Account</code></span></summary><div><table><thead><tr></tr></thead><tbody><tr><td>Id</td><td><div class=\"dni-plaintext\"><pre>2</pre></div></td></tr><tr><td>Code</td><td>002</td></tr><tr><td>Name</td><td>lisi</td></tr><tr><td>Pwd</td><td>123456</td></tr><tr><td>Age</td><td><div class=\"dni-plaintext\"><pre>35</pre></div></td></tr><tr><td>State</td><td><div class=\"dni-plaintext\"><pre>0</pre></div></td></tr></tbody></table></div></details></td></tr></tbody></table><style>\r\n", + ".dni-code-hint {\r\n", + " font-style: italic;\r\n", + " overflow: hidden;\r\n", + " white-space: nowrap;\r\n", + "}\r\n", + ".dni-treeview {\r\n", + " white-space: nowrap;\r\n", + "}\r\n", + ".dni-treeview td {\r\n", + " vertical-align: top;\r\n", + " text-align: start;\r\n", + "}\r\n", + "details.dni-treeview {\r\n", + " padding-left: 1em;\r\n", + "}\r\n", + "table td {\r\n", + " text-align: start;\r\n", + "}\r\n", + "table tr { \r\n", + " vertical-align: top; \r\n", + " margin: 0em 0px;\r\n", + "}\r\n", + "table tr td pre \r\n", + "{ \r\n", + " vertical-align: top !important; \r\n", + " margin: 0em 0px !important;\r\n", + "} \r\n", + "table th {\r\n", + " text-align: start;\r\n", + "}\r\n", + "</style>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "using Microsoft.EntityFrameworkCore;\n", + "using Microsoft.EntityFrameworkCore.SqlServer;\n", + "public class AppDbContext: DbContext\n", + "{\n", + " public DbSet<Account> Accounts {get;set;}\n", + "\n", + " protected override void OnConfiguring(DbContextOptionsBuilder builder)\n", + " {\n", + " builder\n", + " .UseSqlServer(@\"Server=127.0.0.1\\SQL2019;Database=EFCore7Study;User Id=sa;Password=gly-bicijinlian;Encrypt=True;TrustServerCertificate=True;\")\n", + " .EnableSensitiveDataLogging();\n", + " }\n", + "\n", + " protected override void OnModelCreating(ModelBuilder builder)\n", + " {\n", + " builder.Entity<Account>().ToTable(\"Account\");\n", + " base.OnModelCreating(builder);\n", + " }\n", + "}\n", + "\n", + "public class Account\n", + "{\n", + " public int Id { get; set; }\n", + " public string Code { get; set; }\n", + " public string Name { get; set; }\n", + " public string Pwd { get; set; }\n", + "\n", + " public int Age { get; set; }\n", + "\n", + " public int State { get; set; } \n", + "}\n", + "\n", + "using(var db = new AppDbContext())\n", + "{\n", + " var itmes = db.Accounts.ToList();\n", + "\n", + " itmes.Display();\n", + "\n", + "}" + ] } ], "metadata": { diff --git a/Docs/说明.md b/Docs/说明.md index 3b871e4..ce19423 100644 --- a/Docs/说明.md +++ b/Docs/说明.md @@ -1,3 +1,60 @@ # 说明 ======== -EF Core 7的学习总结项目。 \ No newline at end of file +EF Core 7的学习总结项目。 + +## 使用 工厂对象(AddDbContextFactory)时,多构建函数时,IoC获取对象时会异常 +在使用扩展方法 AddDbContextFactory()注册服务时,如果 DbContext有多个构建函数,会在获取服务时因为不知道使用哪个构建函数而异常。 + +解决方案: ++ 不要使用多构造函数 ++ 合并成一个构建函数:比如统一使用 DbContextOptions<T> 参数,非IoC可以手动构建 DbContextOptions<T> 对象当参数 ++ 使用 ActivatorUtilitiesConstructor 特性,指定IoC使用的构造函数 +```csharp +public class AppDbContext : DbContext + { + private string? _connectString; + + public AppDbContext() + { + + } + + public AppDbContext(string? connectstring, string dd = "dd") + { + _connectString = connectstring; + } + + //指定IoC使用的构造函数 + [ActivatorUtilitiesConstructor] + public AppDbContext(DbContextOptions<AppDbContext> options) + : base(options) + { + + } + + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + if (!optionsBuilder.IsConfigured) + { + if (string.IsNullOrWhiteSpace(_connectString)) + { + _connectString = @"Server=127.0.0.1\SQL2019;Database=EFCore7Study;User Id=sa;Password=xxxx;Encrypt=True;TrustServerCertificate=True;"; + } + + optionsBuilder + .UseSqlServer(_connectString) + .EnableSensitiveDataLogging(); + } + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity<Account>().ToTable("Account"); + + base.OnModelCreating(modelBuilder); + } + + public DbSet<Account> Accounts { get; set; } + } +``` \ No newline at end of file diff --git a/EFCore7Study.BlazorServerApp/Pages/Index.razor b/EFCore7Study.BlazorServerApp/Pages/Index.razor index 6085c4a..4ab4055 100644 --- a/EFCore7Study.BlazorServerApp/Pages/Index.razor +++ b/EFCore7Study.BlazorServerApp/Pages/Index.razor @@ -1,9 +1,37 @@ @page "/" +@using EFCore7Study.DataService; +@using EFCore7Study.DataService.Models; +@using Microsoft.EntityFrameworkCore; +@inject IDbContextFactory<AppDbContext> DbFactory <PageTitle>Index</PageTitle> +@foreach(var account in AccountList) +{ + <h2>@(account.Name)</h2> +} + <h1>Hello, world!</h1> Welcome to your new app. <SurveyPrompt Title="How is Blazor working for you?" /> + +@code{ + private List<Account> AccountList { get; set; } = new List<Account>(); + + protected override void OnInitialized() + { + AccountList = GetAccounts(); + base.OnInitialized(); + } + + private List<Account> GetAccounts() + { + using (var context = DbFactory.CreateDbContext()) + { + return context.Accounts.ToList(); + + }; + } +} diff --git a/EFCore7Study.BlazorServerApp/Program.cs b/EFCore7Study.BlazorServerApp/Program.cs index ada4af6..8283be9 100644 --- a/EFCore7Study.BlazorServerApp/Program.cs +++ b/EFCore7Study.BlazorServerApp/Program.cs @@ -1,7 +1,10 @@ using EFCore7Study.BlazorServerApp.Data; +using EFCore7Study.DataService; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Internal; namespace EFCore7Study.BlazorServerApp { @@ -16,6 +19,20 @@ namespace EFCore7Study.BlazorServerApp builder.Services.AddServerSideBlazor(); builder.Services.AddSingleton<WeatherForecastService>(); + //EF Core + var connectString = builder.Configuration.GetConnectionString("SQLServer"); + + + + + + builder.Services.AddDbContextFactory<AppDbContext> + ( + b => b.UseSqlServer(connectString).EnableSensitiveDataLogging(), ServiceLifetime.Scoped + ); + + builder.Services.AddDbContextFactory<AppDbContext>(options => options.UseSqlServer(connectString)); + var app = builder.Build(); // Configure the HTTP request pipeline. diff --git a/EFCore7Study.BlazorServerApp/appsettings.json b/EFCore7Study.BlazorServerApp/appsettings.json index 10f68b8..5ad2086 100644 --- a/EFCore7Study.BlazorServerApp/appsettings.json +++ b/EFCore7Study.BlazorServerApp/appsettings.json @@ -5,5 +5,8 @@ "Microsoft.AspNetCore": "Warning" } }, - "AllowedHosts": "*" + "AllowedHosts": "*", + "ConnectionStrings": { + "SQLServer": "Server=127.0.0.1\\SQL2019;Database=EFCore7Study;User Id=sa;Password=gly-bicijinlian;Encrypt=True;TrustServerCertificate=True;" + } } diff --git a/EFCore7Study.CoreConsoleApp/Program.cs b/EFCore7Study.CoreConsoleApp/Program.cs index 580f256..d71e6fb 100644 --- a/EFCore7Study.CoreConsoleApp/Program.cs +++ b/EFCore7Study.CoreConsoleApp/Program.cs @@ -8,274 +8,53 @@ namespace EFCore7Study.CoreConsoleApp { static void Main(string[] args) { - AnsiConsole.Status() - .Spinner(Spinner.Known.BouncingBar) - .Start("测试一个", ctx => - { - ctx.Spinner(Spinner.Known.BouncingBar); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Aesthetic)); - - ctx.Spinner(Spinner.Known.Arc); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Arc)); - - ctx.Spinner(Spinner.Known.Arrow); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Arrow)); - - ctx.Spinner(Spinner.Known.Arrow2); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Arrow2)); - - ctx.Spinner(Spinner.Known.Arrow3); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Arrow3)); - - ctx.Spinner(Spinner.Known.Balloon); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Balloon)); - - ctx.Spinner(Spinner.Known.Balloon2); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Balloon2)); - - ctx.Spinner(Spinner.Known.BetaWave); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.BetaWave)); - - ctx.Spinner(Spinner.Known.Bounce); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Bounce)); - - ctx.Spinner(Spinner.Known.BouncingBall); - Thread.Sleep(3000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.BouncingBall)); - - ctx.Spinner(Spinner.Known.BouncingBar); - Thread.Sleep(3000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.BouncingBar)); - - ctx.Spinner(Spinner.Known.BoxBounce); - Thread.Sleep(3000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.BoxBounce)); - - ctx.Spinner(Spinner.Known.BoxBounce2); - Thread.Sleep(3000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.BoxBounce2)); - - ctx.Spinner(Spinner.Known.Dots8Bit); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Dots8Bit)); - - ctx.Spinner(Spinner.Known.Christmas); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Christmas)); - - ctx.Spinner(Spinner.Known.Circle); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Circle)); - - ctx.Spinner(Spinner.Known.CircleHalves); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.CircleHalves)); - - ctx.Spinner(Spinner.Known.CircleQuarters); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.CircleQuarters)); - - ctx.Spinner(Spinner.Known.Clock); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Clock)); - - ctx.Spinner(Spinner.Known.Default); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Default)); - - ctx.Spinner(Spinner.Known.Dots); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Dots)); - - ctx.Spinner(Spinner.Known.Dots2); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Dots2)); - - ctx.Spinner(Spinner.Known.Dots8Bit); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Dots8Bit)); - //======================================================== - ctx.Spinner(Spinner.Known.Dqpb); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Dqpb)); - - ctx.Spinner(Spinner.Known.Earth); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Earth)); - - ctx.Spinner(Spinner.Known.Flip); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Flip)); - - ctx.Spinner(Spinner.Known.Grenade); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Grenade)); - - ctx.Spinner(Spinner.Known.GrowHorizontal); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.GrowHorizontal)); - - ctx.Spinner(Spinner.Known.GrowVertical); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.GrowVertical)); - - ctx.Spinner(Spinner.Known.Hamburger); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Hamburger)); - Thread.Sleep(2000); - - ctx.Spinner(Spinner.Known.Hearts); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Hearts)); - - ctx.Spinner(Spinner.Known.Layer); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Layer)); - - ctx.Spinner(Spinner.Known.Line); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Line)); - - ctx.Spinner(Spinner.Known.Line2); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Line2)); - - ctx.Spinner(Spinner.Known.Material); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Material)); - - ctx.Spinner(Spinner.Known.Monkey); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Monkey)); - - ctx.Spinner(Spinner.Known.Moon); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Moon)); - - ctx.Spinner(Spinner.Known.Noise); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Noise)); - - ctx.Spinner(Spinner.Known.Pipe); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Pipe)); - - ctx.Spinner(Spinner.Known.Point); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Dots8Bit)); - - ctx.Spinner(Spinner.Known.Pong); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Pong)); - - ctx.Spinner(Spinner.Known.Runner); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Runner)); - - ctx.Spinner(Spinner.Known.Shark); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Shark)); - - ctx.Spinner(Spinner.Known.SimpleDots); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.SimpleDots)); - - ctx.Spinner(Spinner.Known.SimpleDotsScrolling); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.SimpleDotsScrolling)); - - ctx.Spinner(Spinner.Known.Smiley); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Smiley)); - - ctx.Spinner(Spinner.Known.SquareCorners); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.SquareCorners)); - - ctx.Spinner(Spinner.Known.Squish); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Squish)); - - ctx.Spinner(Spinner.Known.Star); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Star)); - - ctx.Spinner(Spinner.Known.Star2); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Star2)); - - ctx.Spinner(Spinner.Known.Toggle); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Toggle)); - - ctx.Spinner(Spinner.Known.Toggle2); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Toggle2)); - - ctx.Spinner(Spinner.Known.Triangle); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Triangle)); - - ctx.Spinner(Spinner.Known.Weather); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Weather)); - - ctx.Spinner(Spinner.Known.Weather); - Thread.Sleep(2000); - AnsiConsole.MarkupLine(nameof(Spinner.Known.Weather)); - }); + } + static void ShowQuery() + { AnsiConsole.Status() - .Spinner(Spinner.Known.Balloon) - .Start("准备查询数据库...", ctx => - { - Thread.Sleep(2000); - - // 生成查询对象 - ctx.Status("生成查询对象..."); - AppDbContext dbContext = new AppDbContext(); - Thread.Sleep(2000); - AnsiConsole.MarkupLine("生成查询对象: DbContext, 完成!"); - - // 连接数据库 - ctx.Status("正在连接到数据库服务器..."); - ctx.Spinner(Spinner.Known.Balloon); - ctx.SpinnerStyle(Style.Parse("green")); - Thread.Sleep(2000); - AnsiConsole.MarkupLine("已连接到数据库服务器!"); - - - // 查询数据 - ctx.Status("正在查询数据..."); - ctx.Spinner(Spinner.Known.Star2); - ctx.SpinnerStyle(Style.Parse("yellow")); - Thread.Sleep(3000); - AnsiConsole.MarkupLine("完成查询!"); - - - //输出查询结果 - ctx.Status("输出查询结果..."); - ctx.Spinner(Spinner.Known.Arrow); - ctx.SpinnerStyle(Style.Parse("red")); - - dbContext.Accounts.ToList().ForEach(x => - { - AnsiConsole.MarkupLine($"标识:{x.Id},编号:{x.Code}, 姓名:{x.Name.PadRight(10)},年龄:{x.Age}, 密码:{x.Pwd}"); - Thread.Sleep(300); - }); - - AnsiConsole.MarkupLine("任务完成!"); - - }); + .Spinner(Spinner.Known.Balloon) + .Start("准备查询数据库...", ctx => + { + Thread.Sleep(2000); + + // 生成查询对象 + ctx.Status("生成查询对象..."); + AppDbContext dbContext = new AppDbContext(); + //Thread.Sleep(2000); + AnsiConsole.MarkupLine("生成查询对象: DbContext, 完成!"); + + // 连接数据库 + ctx.Status("正在连接到数据库服务器..."); + ctx.Spinner(Spinner.Known.Balloon); + ctx.SpinnerStyle(Style.Parse("green")); + //Thread.Sleep(2000); + AnsiConsole.MarkupLine("已连接到数据库服务器!"); + + + // 查询数据 + ctx.Status("正在查询数据..."); + ctx.Spinner(Spinner.Known.Star2); + ctx.SpinnerStyle(Style.Parse("yellow")); + //Thread.Sleep(3000); + AnsiConsole.MarkupLine("完成查询!"); + + + //输出查询结果 + ctx.Status("输出查询结果..."); + ctx.Spinner(Spinner.Known.Arrow); + ctx.SpinnerStyle(Style.Parse("red")); + + dbContext.Accounts.ToList().ForEach(x => + { + AnsiConsole.MarkupLine($"标识:{x.Id},编号:{x.Code}, 姓名:{x.Name.PadRight(10)},年龄:{x.Age}, 密码:{x.Pwd}"); + Thread.Sleep(300); + }); + + AnsiConsole.MarkupLine("任务完成!"); + + }); } } } \ No newline at end of file diff --git a/EFCore7Study.DataService/AppDbContext.cs b/EFCore7Study.DataService/AppDbContext.cs index 3fb0003..d1922ef 100644 --- a/EFCore7Study.DataService/AppDbContext.cs +++ b/EFCore7Study.DataService/AppDbContext.cs @@ -1,25 +1,27 @@ using EFCore7Study.DataService.Models; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; namespace EFCore7Study.DataService { + /// <summary> + /// 多构造函数 + /// 为使用工厂方式注册,加 ActivatorUtilitiesConstructor 特性 + /// </summary> public class AppDbContext : DbContext { - private string? _connectString; + /// <summary> + /// 连接字符串,可实现属性设置,避免多构造函数在Factory时,IoC异常 + /// </summary> + public string? ConnectString = @"Server=127.0.0.1\SQL2019;Database=EFCore7Study;User Id=sa;Password=gly-bicijinlian;Encrypt=True;TrustServerCertificate=True;"; public AppDbContext() { } - public AppDbContext(string connectstring) - { - _connectString = connectstring; - } - - public AppDbContext(DbContextOptions<AppDbContext> options) - : base(options) + public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { } @@ -28,13 +30,13 @@ namespace EFCore7Study.DataService { if (!optionsBuilder.IsConfigured) { - if (string.IsNullOrWhiteSpace(_connectString)) + if (string.IsNullOrWhiteSpace(ConnectString)) { - _connectString = @"Server=127.0.0.1\SQL2019;Database=EFCore7Study;User Id=sa;Password=gly-bicijinlian;Encrypt=True;TrustServerCertificate=True;"; + ConnectString = @"Server=127.0.0.1\SQL2019;Database=EFCore7Study;User Id=sa;Password=gly-bicijinlian;Encrypt=True;TrustServerCertificate=True;"; } optionsBuilder - .UseSqlServer(_connectString) + .UseSqlServer(ConnectString) .EnableSensitiveDataLogging(); } } diff --git a/EFCore7Study.DataService/AppDbContext2.cs b/EFCore7Study.DataService/AppDbContext2.cs new file mode 100644 index 0000000..21fc10a --- /dev/null +++ b/EFCore7Study.DataService/AppDbContext2.cs @@ -0,0 +1,49 @@ +using EFCore7Study.DataService.Models; + +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure.Internal; +using Microsoft.Extensions.DependencyInjection; + +namespace EFCore7Study.DataService +{ + /// <summary> + /// 多构造函数 + /// 为使用工厂方式注册,合并为一个 + /// </summary> + public class AppDbContext2 : DbContext + { + private string? _connectString; + + //因为先执行的 base(options),到此处时AppDbContext2已经注册完成,连接字符串实际上是用不了的。当然换成其它参数或用在其它地方是可以的。 + public AppDbContext2(DbContextOptions<AppDbContext2> options, string? connectString = null) + : base(options) + { + _connectString = connectString; + } + + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + if (!optionsBuilder.IsConfigured) + { + if (string.IsNullOrWhiteSpace(_connectString)) + { + _connectString = @"Server=127.0.0.1\SQL2019;Database=EFCore7Study;User Id=sa;Password=gly-bicijinlian;Encrypt=True;TrustServerCertificate=True;"; + } + + optionsBuilder + .UseSqlServer(_connectString) + .EnableSensitiveDataLogging(); + } + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity<Account>().ToTable("Account"); + + base.OnModelCreating(modelBuilder); + } + + public DbSet<Account> Accounts { get; set; } + } +} \ No newline at end of file diff --git a/EFCore7Study.DataService/AppDbContext3.cs b/EFCore7Study.DataService/AppDbContext3.cs new file mode 100644 index 0000000..8eae800 --- /dev/null +++ b/EFCore7Study.DataService/AppDbContext3.cs @@ -0,0 +1,58 @@ +using EFCore7Study.DataService.Models; + +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; + +namespace EFCore7Study.DataService +{ + /// <summary> + /// 多构造函数 + /// 使用工厂对象(AddDbContextFactory)时,因多构建函数,IoC 获取对象时会异常 + /// </summary> + public class AppDbContext3 : DbContext + { + private string? _connectString; + + public AppDbContext3() + { + + } + + public AppDbContext3(string? connectstring) + { + _connectString = connectstring; + } + + + public AppDbContext3(DbContextOptions<AppDbContext> options) + : base(options) + { + + } + + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + if (!optionsBuilder.IsConfigured) + { + if (string.IsNullOrWhiteSpace(_connectString)) + { + _connectString = @"Server=127.0.0.1\SQL2019;Database=EFCore7Study;User Id=sa;Password=gly-bicijinlian;Encrypt=True;TrustServerCertificate=True;"; + } + + optionsBuilder + .UseSqlServer(_connectString) + .EnableSensitiveDataLogging(); + } + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity<Account>().ToTable("Account"); + + base.OnModelCreating(modelBuilder); + } + + public DbSet<Account> Accounts { get; set; } + } +} \ No newline at end of file diff --git a/EFCore7Study.DataService/Models/Account.cs b/EFCore7Study.DataService/Models/Account.cs index b8bc6a3..09557fa 100644 --- a/EFCore7Study.DataService/Models/Account.cs +++ b/EFCore7Study.DataService/Models/Account.cs @@ -6,9 +6,9 @@ public class Account { public int Id { get; set; } - public string Code { get; set; } - public string Name { get; set; } - public string Pwd { get; set; } + public string Code { get; set; } = ""; + public string Name { get; set; } = ""; + public string Pwd { get; set; } = ""; public int Age { get; set; } diff --git a/EFCore7Study.WebApi/Controllers/AccountsController.cs b/EFCore7Study.WebApi/Controllers/AccountsController.cs new file mode 100644 index 0000000..a6ad7e5 --- /dev/null +++ b/EFCore7Study.WebApi/Controllers/AccountsController.cs @@ -0,0 +1,26 @@ +using EFCore7Study.DataService; +using EFCore7Study.DataService.Models; + +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace EFCore7Study.WebApi.Controllers +{ + [Route("api/[controller]/[action]")] + [ApiController] + public class AccountsController : ControllerBase + { + private readonly AppDbContext _dbContext; + + public AccountsController(AppDbContext context) + { + _dbContext = context; + } + + [HttpGet] + public List<Account> AllAccounts() + { + return _dbContext.Accounts.ToList(); + } + } +} diff --git a/EFCore7Study.WebApi/Controllers/EFCore2Controller.cs b/EFCore7Study.WebApi/Controllers/EFCore2Controller.cs new file mode 100644 index 0000000..eeb1020 --- /dev/null +++ b/EFCore7Study.WebApi/Controllers/EFCore2Controller.cs @@ -0,0 +1,43 @@ +using EFCore7Study.DataService; +using EFCore7Study.DataService.Models; + +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Internal; + +namespace EFCore7Study.WebApi.Controllers +{ + [Route("api/[controller]/[action]")] + [ApiController] + public class EFCore2Controller : ControllerBase + { + private readonly AppDbContext2 _context; + private readonly IDbContextFactory<AppDbContext2> _factory; + + public EFCore2Controller + ( + AppDbContext2 context, + IDbContextFactory<AppDbContext2> factory + ) + { + _context = context; + _factory = factory; + } + + [HttpGet] + public List<Account> GetAll() + { + return _context.Accounts.AsNoTracking().ToList(); + } + + [HttpGet] + public List<Account> GetAllByFactory() + { + using (var db = _factory.CreateDbContext()) + { + return db.Accounts.AsNoTracking().ToList(); + } + } + } +} diff --git a/EFCore7Study.WebApi/Controllers/EFCore3Controller.cs b/EFCore7Study.WebApi/Controllers/EFCore3Controller.cs new file mode 100644 index 0000000..be18a9d --- /dev/null +++ b/EFCore7Study.WebApi/Controllers/EFCore3Controller.cs @@ -0,0 +1,60 @@ +using EFCore7Study.DataService; +using EFCore7Study.DataService.Models; + +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Internal; + +namespace EFCore7Study.WebApi.Controllers +{ + [Route("api/[controller]/[action]")] + [ApiController] + public class EFCore3Controller : ControllerBase + { + + private readonly IDbContextFactory<AppDbContext3> _contextFactory; + + public EFCore3Controller(IDbContextFactory<AppDbContext3> contextFactory) + { + _contextFactory = contextFactory; + } + + + [HttpGet] + public List<Account> GetAll() + { + return _contextFactory.CreateDbContext().Accounts.ToList(); + } + + [HttpGet] + public List<Account> GetAll2() + { + return _contextFactory.CreateDbContext().Accounts.ToList(); + } + + [HttpGet] + public List<Account> GetAll3() + { + return _contextFactory.CreateDbContext().Accounts.ToList(); + } + + [HttpGet] + public List<Account> GetAll4() + { + return _contextFactory.CreateDbContext().Accounts.ToList(); + } + + [HttpGet] + public List<Account> GetAll5() + { + return _contextFactory.CreateDbContext().Accounts.ToList(); + } + + [HttpGet] + public List<Account> GetAll6() + { + return _contextFactory.CreateDbContext().Accounts.ToList(); + } + } +} diff --git a/EFCore7Study.WebApi/Controllers/EFCoreController.cs b/EFCore7Study.WebApi/Controllers/EFCoreController.cs new file mode 100644 index 0000000..71a7989 --- /dev/null +++ b/EFCore7Study.WebApi/Controllers/EFCoreController.cs @@ -0,0 +1,63 @@ +using EFCore7Study.DataService; +using EFCore7Study.DataService.Models; + +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace EFCore7Study.WebApi.Controllers +{ + [Route("api/[controller]/[action]")] + [ApiController] + public class EFCoreController : ControllerBase + { + private readonly AppDbContext _connect; + private readonly IDbContextFactory<AppDbContext> _factory; + + public EFCoreController(AppDbContext context, IDbContextFactory<AppDbContext> factory) + { + _connect = context; + _factory = factory; + } + + + [HttpGet] + public List<Account> GetAll() + { + return _connect.Accounts.ToList(); + } + + [HttpGet] + public List<Account> GetAllByFactory() + { + using (var db = _factory.CreateDbContext()) + { + return db.Accounts.ToList(); + } + } + + [HttpGet] + public List<Account> GetAll3() + { + return _connect.Accounts.ToList(); + } + + [HttpGet] + public List<Account> GetAll4() + { + return _connect.Accounts.ToList(); + } + + [HttpGet] + public List<Account> GetAll5() + { + return _connect.Accounts.ToList(); + } + + [HttpGet] + public List<Account> GetAll6() + { + return _connect.Accounts.ToList(); + } + } +} diff --git a/EFCore7Study.WebApi/EFCore7Study.WebApi.csproj b/EFCore7Study.WebApi/EFCore7Study.WebApi.csproj index d6f9db3..7fbf2db 100644 --- a/EFCore7Study.WebApi/EFCore7Study.WebApi.csproj +++ b/EFCore7Study.WebApi/EFCore7Study.WebApi.csproj @@ -12,4 +12,8 @@ <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" /> </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\EFCore7Study.DataService\EFCore7Study.DataService.csproj" /> + </ItemGroup> + </Project> diff --git a/EFCore7Study.WebApi/Program.cs b/EFCore7Study.WebApi/Program.cs index 2cc1c2d..137f58e 100644 --- a/EFCore7Study.WebApi/Program.cs +++ b/EFCore7Study.WebApi/Program.cs @@ -1,3 +1,7 @@ +using EFCore7Study.DataService; + +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.SqlServer; namespace EFCore7Study.WebApi { @@ -14,9 +18,132 @@ namespace EFCore7Study.WebApi builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); - var app = builder.Build(); + //注册服务:EFCore + #region 注册服务:EFCore + var connectString = builder.Configuration.GetConnectionString("SQLServer"); + var contextOptionsBuilder = new DbContextOptionsBuilder<AppDbContext>() + .UseSqlServer(connectString) + .EnableSensitiveDataLogging(); + var contextOptions = contextOptionsBuilder.Options; + + //方式一:默认构造,使用内部数据连接 + //builder.Services.AddScoped(provider => new AppDbContext()); + + //方式二: 设置连接字符串属性 + //builder.Services.AddScoped(provider => + //{ + // var db = new AppDbContext(); + // db.ConnectString = connectString; + // return db; + //}); + + //方法三:使用 DbContextOptions 的构建函数 [比较推荐] + //builder.Services.AddScoped<AppDbContext>(provider => new AppDbContext(contextOptions)); + + //方式四:使用 AddDbContext 扩展方法 [官方推荐] + //小问题:会覆盖之前方法的服务注册,猜测内部进行过去重复处理过,要验证请使用 GetServices 获取所有注册的服务。 + //解决:方法三放在方法四后面 + //builder.Services.AddDbContext<AppDbContext>(option => + //{ + // //从配置中获取连接字符串 + // option.UseSqlServer(connectString) + // .EnableSensitiveDataLogging(); + //}); + + //方式五: 使用 DbContextFactory 工厂 + //注意: + // 1、此方法与方法四都是注册的 AppDbContext对象,方法四默认为Scoped,此方式默认为单例,两者的冲突导致异常 + // 2、此方法与方法四,都会覆盖之前的 AppDbContext 注册 + //解决: + // 1、此方法不与方法4同用,如果要同时使用,请使用方法1-3 + // 2、使此方法与方法四,应用相同生命周期 + //builder.Services.AddDbContextFactory<AppDbContext>(optionBuilder => + //{ + // optionBuilder.UseSqlServer(connectString) + // .EnableSensitiveDataLogging(); + //}); + + //使用自定的覆盖工厂的AppDbContext,但工厂本身的IDbContextFactory<AppDbContext>不会覆盖,可以分开使用。 + //builder.Services.AddScoped<AppDbContext>(provider => new AppDbContext(contextOptions)); + + //方式六:使用 DbContextPool 池 + builder.Services.AddDbContextPool<AppDbContext>((provider, optionBuilder) => + { + //provider.GetRequiredService<AppDbContext>(); + optionBuilder.UseSqlServer(connectString) + .EnableSensitiveDataLogging(); + }, poolSize: 2048); + + //方式七:使用连接池的工厂 + builder.Services.AddPooledDbContextFactory<AppDbContext>((serviceProvider, optionBuilder) => + { + //serviceProvider.GetRequiredService<AppDbContext>(); + + optionBuilder.UseSqlServer(connectString) + .EnableSensitiveDataLogging(); + }, poolSize: 1024); + + //使用自定的覆盖工厂的AppDbContext,但工厂本身的IDbContextFactory<AppDbContext>不会覆盖,可以分开使用。 + builder.Services.AddScoped(provider => new AppDbContext()); + + //获取所有注册的服务(可没查看是否覆盖注册) + //var dd = builder?.Services?.BuildServiceProvider().GetServices<AppDbContext>(); + #endregion + + #region 注册服务:EFCore2 + + var contextOptionBuilder2 = new DbContextOptionsBuilder<AppDbContext2>() + .UseSqlServer(connectString) + .EnableSensitiveDataLogging(); + DbContextOptions<AppDbContext2>? contextOptions2 = contextOptionBuilder2.Options; + + //方法:使用 统一构建函数 + //builder.Services.AddScoped<AppDbContext2>(provider => new AppDbContext2(contextOptions)); + //或者 + builder?.Services.AddScoped(provider => new AppDbContext2(contextOptions2, connectString)); + + //方式:使用 AddDbContext 扩展方法 [官方推荐] + //builder.Services.AddDbContext<AppDbContext2>((server, option) => + //{ + // //从配置中获取连接字符串 + // //builder.Configuration.GetConnectionString("SQLServer"); + + // //设置 + // option.UseSqlServer(connectString) + // .EnableSensitiveDataLogging(); + //}); + + //方式: 使用 DbContextFactory 工厂 + //builder.Services.AddDbContextFactory<AppDbContext2>(optionBuilder => + //{ + // optionBuilder.UseSqlServer(connectString) + // .EnableSensitiveDataLogging(); + //}, ServiceLifetime.Scoped); + + //或者 + //builder.Services.AddDbContextFactory<AppDbContext2>((provider, builder) => + //{ + + + //}, ServiceLifetime.Scoped); + + //方式:使用 DbContextPool 池 + //builder.Services.AddDbContextPool<AppDbContext2>(optionBuilder => + //{ + // optionBuilder.UseSqlServer(connectString) + // .EnableSensitiveDataLogging(); + //}); + + //方式:使用连接池的工厂 + //builder.Services.AddPooledDbContextFactory<AppDbContext2>(optionBuilder => + //{ + // optionBuilder.UseSqlServer(connectString) + // .EnableSensitiveDataLogging(); + //}); + #endregion + + var app = builder!.Build(); - // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); diff --git a/EFCore7Study.WebApi/appsettings.json b/EFCore7Study.WebApi/appsettings.json index 10f68b8..5ad2086 100644 --- a/EFCore7Study.WebApi/appsettings.json +++ b/EFCore7Study.WebApi/appsettings.json @@ -5,5 +5,8 @@ "Microsoft.AspNetCore": "Warning" } }, - "AllowedHosts": "*" + "AllowedHosts": "*", + "ConnectionStrings": { + "SQLServer": "Server=127.0.0.1\\SQL2019;Database=EFCore7Study;User Id=sa;Password=gly-bicijinlian;Encrypt=True;TrustServerCertificate=True;" + } }