From b55a45baa2be76870c13825759559d4b38d7f98a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A9=99=E5=AD=90?= <454313500@qq.com> Date: Thu, 20 Apr 2023 22:36:32 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E5=AE=8C=E6=88=90codefirst=E4=B8=8E?= =?UTF-8?q?=E7=A7=8D=E5=AD=90=E6=95=B0=E6=8D=AE=EF=BC=8C=E5=8F=91=E7=8E=B0?= =?UTF-8?q?=E9=9D=9E=E7=A9=BA=E7=B1=BB=E5=9E=8B=E9=97=AE=E9=A2=98=EF=BC=8C?= =?UTF-8?q?=E7=AD=89=E5=BE=85=E7=B4=A7=E6=80=A5=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Data/DataSeeds/DataSeedExtensions.cs | 16 ++--- .../Sqlsugar/SqlsugarCodeFirstExtensions.cs | 61 ++++++++++++++++++ .../Yi.Framework.Infrastructure/Startup.cs | 9 ++- .../Rbac/DataSeeds/MenuDataSeed.cs | 17 ++++- .../Rbac/Entities/DeptEntity.cs | 4 +- .../Rbac/Entities/MenuEntity.cs | 12 ++-- .../Rbac/Entities/PostEntity.cs | 2 +- .../Rbac/Entities/UserEntity.cs | 14 ++-- .../Yi.Furion.Core/Yi.Furion.Core.csproj | 1 + .../Yi.Furion.Web.Entry/SingleFilePublish.cs | 10 +-- .../Yi.Furion.Web.Entry.csproj | 14 +++- .../Yi.Furion.Web.Entry/appsettings.json | 11 ++-- .../Yi.Furion.Web.Entry/yi-sqlsugar-dev.db | Bin 0 -> 221184 bytes 13 files changed, 131 insertions(+), 40 deletions(-) create mode 100644 Yi.Furion.Net6/Yi.Framework.Infrastructure/Sqlsugar/SqlsugarCodeFirstExtensions.cs diff --git a/Yi.Furion.Net6/Yi.Framework.Infrastructure/Data/DataSeeds/DataSeedExtensions.cs b/Yi.Furion.Net6/Yi.Framework.Infrastructure/Data/DataSeeds/DataSeedExtensions.cs index a83a8155..292d1270 100644 --- a/Yi.Furion.Net6/Yi.Framework.Infrastructure/Data/DataSeeds/DataSeedExtensions.cs +++ b/Yi.Furion.Net6/Yi.Framework.Infrastructure/Data/DataSeeds/DataSeedExtensions.cs @@ -26,23 +26,23 @@ namespace Yi.Framework.Infrastructure.Data.DataSeeds { //using (var uow = iUnitOfWorkManager.CreateContext()) //{ - var res = await iUnitOfWorkManager.Ado.UseTranAsync(async () => - { + //var res = await iUnitOfWorkManager.Ado.UseTranAsync(async () => + // { foreach (var seed in dataSeeds) { await seed.InvokerAsync(); } - }); + //}); //var res = uow.Commit(); - if (!res.IsSuccess) - { - throw new ApplicationException("种子数据初始化异常"); - } + //if (!res.IsSuccess) + //{ + //throw new ApplicationException("种子数据初始化异常"); + //} //} } - return builder.UseMiddleware(); + return builder; } } } diff --git a/Yi.Furion.Net6/Yi.Framework.Infrastructure/Sqlsugar/SqlsugarCodeFirstExtensions.cs b/Yi.Furion.Net6/Yi.Framework.Infrastructure/Sqlsugar/SqlsugarCodeFirstExtensions.cs new file mode 100644 index 00000000..20582d9f --- /dev/null +++ b/Yi.Furion.Net6/Yi.Framework.Infrastructure/Sqlsugar/SqlsugarCodeFirstExtensions.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Furion; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using SqlSugar; + +namespace Yi.Framework.Infrastructure.Sqlsugar +{ + public static class SqlsugarCodeFirstExtensions + { + public static void UseSqlsugarCodeFirstServer(this IApplicationBuilder app) + { + var db = app.ApplicationServices.GetRequiredService(); + var options = app.ApplicationServices.GetRequiredService>(); + + if (options.Value.EnabledCodeFirst == false) return; + + db.DbMaintenance.CreateDatabase(); + var assemblys = new List(); + + //全盘加载 + if (options.Value.EntityAssembly is null) + { + assemblys.AddRange(App.Assemblies.ToList()); + } + //按需加载 + else + { + options.Value.EntityAssembly.ForEach(a => + { + assemblys.Add(Assembly.Load(a)); + }); + } + + foreach (var assembly in assemblys) + { + TableInvoer(db, assembly.GetTypes().ToList()); + } + + } + + private static void TableInvoer(ISqlSugarClient _Db, List typeList) + { + foreach (var t in typeList) + { + //扫描如果存在SugarTable特性 并且 不是分表模型,直接codefirst + if (t.GetCustomAttributes(false).Any(a => a.GetType().Equals(typeof(SugarTable)) + && !t.GetCustomAttributes(false).Any(a => a.GetType().Equals(typeof(SplitTableAttribute))))) + { + _Db.CodeFirst.SetStringDefaultLength(200).InitTables(t);//这样一个表就能成功创建了 + } + } + } + } +} diff --git a/Yi.Furion.Net6/Yi.Framework.Infrastructure/Startup.cs b/Yi.Furion.Net6/Yi.Framework.Infrastructure/Startup.cs index b391068b..c5d439a9 100644 --- a/Yi.Furion.Net6/Yi.Framework.Infrastructure/Startup.cs +++ b/Yi.Furion.Net6/Yi.Framework.Infrastructure/Startup.cs @@ -7,6 +7,7 @@ using StackExchange.Profiling.SqlFormatters; using Yi.Framework.Infrastructure.AspNetCore; using Yi.Framework.Infrastructure.Auth; using Yi.Framework.Infrastructure.Data; +using Yi.Framework.Infrastructure.Data.DataSeeds; using Yi.Framework.Infrastructure.Data.Filters; using Yi.Framework.Infrastructure.Sqlsugar; using Yi.Framework.Infrastructure.Sqlsugar.Filters; @@ -31,13 +32,17 @@ public class Startup : AppStartup services.AddSingleton(); services.AddSingleton(); - services.AddControllers(options => { + services.AddControllers(options => + { options.Filters.Add(); }); } - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + public async void Configure(IApplicationBuilder app, IWebHostEnvironment env) { + app.UseSqlsugarCodeFirstServer(); + await app.UseDataSeedServer(); app.UseDataFiterServer(); + } } diff --git a/Yi.Furion.Net6/Yi.Furion.Core/Rbac/DataSeeds/MenuDataSeed.cs b/Yi.Furion.Net6/Yi.Furion.Core/Rbac/DataSeeds/MenuDataSeed.cs index 7ccbe18f..512650c2 100644 --- a/Yi.Furion.Net6/Yi.Furion.Core/Rbac/DataSeeds/MenuDataSeed.cs +++ b/Yi.Furion.Net6/Yi.Furion.Core/Rbac/DataSeeds/MenuDataSeed.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Linq; +using System.Threading.Tasks; using Yi.Framework.Infrastructure.Data.DataSeeds; using Yi.Framework.Infrastructure.Ddd.Repositories; using Yi.Framework.Infrastructure.Helper; @@ -89,7 +90,7 @@ namespace Yi.Furion.Core.Rbac.DataSeeds ParentId = monitoring.Id, IsDeleted = false }; - entities.Add(online); + entities.Add(cache); //服务监控 MenuEntity server = new MenuEntity() @@ -108,7 +109,7 @@ namespace Yi.Furion.Core.Rbac.DataSeeds ParentId = monitoring.Id, IsDeleted = false }; - entities.Add(online); + entities.Add(server); //系统工具 @@ -1104,6 +1105,16 @@ namespace Yi.Furion.Core.Rbac.DataSeeds m.IsDeleted = false; m.State = true; }); + + var p = entities.GroupBy(x => x.Id); + foreach (var k in p) + { + if (k.ToList().Count > 1) + { + Console.WriteLine("菜单id重复"); + } + + } return entities; } } diff --git a/Yi.Furion.Net6/Yi.Furion.Core/Rbac/Entities/DeptEntity.cs b/Yi.Furion.Net6/Yi.Furion.Core/Rbac/Entities/DeptEntity.cs index 3feaae8c..e593c928 100644 --- a/Yi.Furion.Net6/Yi.Furion.Core/Rbac/Entities/DeptEntity.cs +++ b/Yi.Furion.Net6/Yi.Furion.Core/Rbac/Entities/DeptEntity.cs @@ -69,7 +69,7 @@ namespace Yi.Furion.Core.Rbac.Entities /// 负责人 /// [SugarColumn(ColumnName = "Leader")] - public string Leader { get; set; } + public string? Leader { get; set; } /// /// 父级id /// @@ -80,6 +80,6 @@ namespace Yi.Furion.Core.Rbac.Entities /// 描述 /// [SugarColumn(ColumnName = "Remark")] - public string Remark { get; set; } + public string? Remark { get; set; } } } diff --git a/Yi.Furion.Net6/Yi.Furion.Core/Rbac/Entities/MenuEntity.cs b/Yi.Furion.Net6/Yi.Furion.Core/Rbac/Entities/MenuEntity.cs index de726a14..ba87a20c 100644 --- a/Yi.Furion.Net6/Yi.Furion.Core/Rbac/Entities/MenuEntity.cs +++ b/Yi.Furion.Net6/Yi.Furion.Core/Rbac/Entities/MenuEntity.cs @@ -71,7 +71,7 @@ namespace Yi.Furion.Core.Rbac.Entities /// /// [SugarColumn(ColumnName = "PermissionCode")] - public string PermissionCode { get; set; } + public string? PermissionCode { get; set; } /// /// /// @@ -82,12 +82,12 @@ namespace Yi.Furion.Core.Rbac.Entities /// 菜单图标 /// [SugarColumn(ColumnName = "MenuIcon")] - public string MenuIcon { get; set; } + public string? MenuIcon { get; set; } /// /// 菜单组件路由 /// [SugarColumn(ColumnName = "Router")] - public string Router { get; set; } + public string? Router { get; set; } /// /// 是否为外部链接 /// @@ -108,17 +108,17 @@ namespace Yi.Furion.Core.Rbac.Entities /// 描述 /// [SugarColumn(ColumnName = "Remark")] - public string Remark { get; set; } + public string? Remark { get; set; } /// /// 组件路径 /// [SugarColumn(ColumnName = "Component")] - public string Component { get; set; } + public string? Component { get; set; } /// /// 路由参数 /// [SugarColumn(ColumnName = "Query")] - public string Query { get; set; } + public string? Query { get; set; } [SugarColumn(IsIgnore = true)] public List Children { get; set; } diff --git a/Yi.Furion.Net6/Yi.Furion.Core/Rbac/Entities/PostEntity.cs b/Yi.Furion.Net6/Yi.Furion.Core/Rbac/Entities/PostEntity.cs index 5e2d5426..7e04e9a4 100644 --- a/Yi.Furion.Net6/Yi.Furion.Core/Rbac/Entities/PostEntity.cs +++ b/Yi.Furion.Net6/Yi.Furion.Core/Rbac/Entities/PostEntity.cs @@ -69,6 +69,6 @@ namespace Yi.Furion.Core.Rbac.Entities /// 描述 /// [SugarColumn(ColumnName = "Remark")] - public string Remark { get; set; } + public string? Remark { get; set; } } } diff --git a/Yi.Furion.Net6/Yi.Furion.Core/Rbac/Entities/UserEntity.cs b/Yi.Furion.Net6/Yi.Furion.Core/Rbac/Entities/UserEntity.cs index c7c7675a..fa40343a 100644 --- a/Yi.Furion.Net6/Yi.Furion.Core/Rbac/Entities/UserEntity.cs +++ b/Yi.Furion.Net6/Yi.Furion.Core/Rbac/Entities/UserEntity.cs @@ -68,28 +68,28 @@ namespace Yi.Furion.Core.Rbac.Entities /// /// 头像 /// - public string Icon { get; set; } + public string? Icon { get; set; } /// /// 昵称 /// - public string Nick { get; set; } + public string? Nick { get; set; } /// /// 邮箱 /// - public string Email { get; set; } + public string? Email { get; set; } /// /// Ip /// - public string Ip { get; set; } + public string? Ip { get; set; } /// /// 地址 /// - public string Address { get; set; } + public string? Address { get; set; } /// /// 电话 @@ -99,12 +99,12 @@ namespace Yi.Furion.Core.Rbac.Entities /// /// 简介 /// - public string Introduction { get; set; } + public string? Introduction { get; set; } /// /// 备注 /// - public string Remark { get; set; } + public string? Remark { get; set; } /// /// 性别 diff --git a/Yi.Furion.Net6/Yi.Furion.Core/Yi.Furion.Core.csproj b/Yi.Furion.Net6/Yi.Furion.Core/Yi.Furion.Core.csproj index b40a0b65..8dc398d3 100644 --- a/Yi.Furion.Net6/Yi.Furion.Core/Yi.Furion.Core.csproj +++ b/Yi.Furion.Net6/Yi.Furion.Core/Yi.Furion.Core.csproj @@ -4,6 +4,7 @@ net6.0 1701;1702;1591 Yi.Furion.Core.xml + enable diff --git a/Yi.Furion.Net6/Yi.Furion.Web.Entry/SingleFilePublish.cs b/Yi.Furion.Net6/Yi.Furion.Web.Entry/SingleFilePublish.cs index e34ffe45..91494e2b 100644 --- a/Yi.Furion.Net6/Yi.Furion.Web.Entry/SingleFilePublish.cs +++ b/Yi.Furion.Net6/Yi.Furion.Web.Entry/SingleFilePublish.cs @@ -14,10 +14,12 @@ public class SingleFilePublish : ISingleFilePublish { return new[] { - "Yi.Furion.Rbac.Application", - "Yi.Furion.Rbac.Core", - "Yi.Furion.Rbac.EntityFramework.Core", - "Yi.Furion.Rbac.Web.Core" + "Yi.Framework.Infrastructure", + "Yi.Framework.Module", + "Yi.Furion.Application", + "Yi.Furion.Core", + "Yi.Furion.Sqlsugar.Core", + "Yi.Furion.Core" }; } } \ No newline at end of file diff --git a/Yi.Furion.Net6/Yi.Furion.Web.Entry/Yi.Furion.Web.Entry.csproj b/Yi.Furion.Net6/Yi.Furion.Web.Entry/Yi.Furion.Web.Entry.csproj index de877f78..5207c039 100644 --- a/Yi.Furion.Net6/Yi.Furion.Web.Entry/Yi.Furion.Web.Entry.csproj +++ b/Yi.Furion.Net6/Yi.Furion.Web.Entry/Yi.Furion.Web.Entry.csproj @@ -30,9 +30,6 @@ Always - - Always - @@ -42,6 +39,17 @@ + + + + + + Always + + + Always + + diff --git a/Yi.Furion.Net6/Yi.Furion.Web.Entry/appsettings.json b/Yi.Furion.Net6/Yi.Furion.Web.Entry/appsettings.json index 7514d8c2..62fe5d64 100644 --- a/Yi.Furion.Net6/Yi.Furion.Web.Entry/appsettings.json +++ b/Yi.Furion.Net6/Yi.Furion.Web.Entry/appsettings.json @@ -19,20 +19,22 @@ "DbType": "Sqlite", "EnabledReadWrite": false, "EnabledCodeFirst": false, - "EntityAssembly": null, "ReadUrl": [ "DataSource=[xxxx]", //Sqlite "server=[xxxx];port=3306;database=[xxxx];user id=[xxxx];password=[xxxx]", //Mysql "Data Source=[xxxx];Initial Catalog=[xxxx];User ID=[xxxx];password=[xxxx]" //Sqlserver ] }, + + "EnabledDataSeed": false, + "JWTSettings": { "ValidateIssuerSigningKey": true, // 是否验证密钥,bool 类型,默认true - "IssuerSigningKey": "你的密钥", // 密钥,string 类型,必须是复杂密钥,长度大于16 + "IssuerSigningKey": "123456qwerty123456qwerty", // 密钥,string 类型,必须是复杂密钥,长度大于16 "ValidateIssuer": true, // 是否验证签发方,bool 类型,默认true - "ValidIssuer": "签发方", // 签发方,string 类型 + "ValidIssuer": "ccnetcore", // 签发方,string 类型 "ValidateAudience": true, // 是否验证签收方,bool 类型,默认true - "ValidAudience": "签收方", // 签收方,string 类型 + "ValidAudience": "ccnetcore", // 签收方,string 类型 "ValidateLifetime": true, // 是否验证过期时间,bool 类型,默认true,建议true "ExpiredTime": 20, // 过期时间,long 类型,单位分钟,默认20分钟 "ClockSkew": 5, // 过期时间容错值,long 类型,单位秒,默认 5秒 @@ -46,6 +48,7 @@ "TemplateCode": "", "EnableFeature": false }, + //redis缓存 "CachingConnOptions": { "Host": "", "DB": "", diff --git a/Yi.Furion.Net6/Yi.Furion.Web.Entry/yi-sqlsugar-dev.db b/Yi.Furion.Net6/Yi.Furion.Web.Entry/yi-sqlsugar-dev.db index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5917a2f815629d7abf4e409aa9a1f47657fd65f0 100644 GIT binary patch literal 221184 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 b)m&WTwW!T{J