From 7797edebf175c40d0c70fc2efb215a4ac181beb1 Mon Sep 17 00:00:00 2001 From: 28810 <28810@YEXIANGQIN> Date: Wed, 11 Dec 2019 22:38:41 +0800 Subject: [PATCH] =?UTF-8?q?-=20=E5=A2=9E=E5=8A=A0=20FreeSql.Generator=20?= =?UTF-8?q?=E5=AE=9E=E4=BD=93=E7=B1=BB=E7=94=9F=E6=88=90=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Extensions/FreeSql.Generator/ConsoleApp.cs | 234 +++++++++++++++++ .../FreeSql.Generator.csproj | 33 +++ Extensions/FreeSql.Generator/Program.cs | 22 ++ .../FreeSql.Generator/RazorContentManager.cs | 246 ++++++++++++++++++ Extensions/FreeSql.Generator/RazorModel.cs | 145 +++++++++++ FreeSql.sln | 15 ++ readme.md | 8 +- 7 files changed, 696 insertions(+), 7 deletions(-) create mode 100644 Extensions/FreeSql.Generator/ConsoleApp.cs create mode 100644 Extensions/FreeSql.Generator/FreeSql.Generator.csproj create mode 100644 Extensions/FreeSql.Generator/Program.cs create mode 100644 Extensions/FreeSql.Generator/RazorContentManager.cs create mode 100644 Extensions/FreeSql.Generator/RazorModel.cs diff --git a/Extensions/FreeSql.Generator/ConsoleApp.cs b/Extensions/FreeSql.Generator/ConsoleApp.cs new file mode 100644 index 00000000..4e456fc5 --- /dev/null +++ b/Extensions/FreeSql.Generator/ConsoleApp.cs @@ -0,0 +1,234 @@ +using RazorEngine.Templating; +using System; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using Console = Colorful.Console; + +namespace FreeSql.Generator +{ + class ConsoleApp + { + string ArgsRazorRaw { get; } + string ArgsRazor { get; } + bool[] ArgsNameOptions { get; } + string ArgsNameSpace { get; } + DataType ArgsDbType { get; } + string ArgsConnectionString { get; } + string ArgsFileName { get; } + string ArgsOutput { get; } + + public ConsoleApp(string[] args, ManualResetEvent wait) + { + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + var gb2312 = Encoding.GetEncoding("GB2312"); + if (gb2312 != null) + { + try + { + Console.OutputEncoding = gb2312; + Console.InputEncoding = gb2312; + } + catch { } + } + + //var ntjson = Assembly.LoadFile(@"C:\Users\28810\Desktop\testfreesql\bin\Debug\netcoreapp2.2\publish\testfreesql.dll"); + + //using (var gen = new Generator(new GeneratorOptions())) + //{ + // gen.TraceLog = log => Console.WriteFormatted(log + "\r\n", Color.DarkGray); + // gen.Build(ArgsOutput, new[] { typeof(ojbk.Entities.AuthRole) }, false); + //} + + var version = "v" + string.Join(".", typeof(ConsoleApp).Assembly.GetName().Version.ToString().Split('.').Where((a, b) => b <= 2)); + Console.WriteAscii(" FreeSql", Color.Violet); + Console.WriteFormatted(@" + # Github # {0} {1} +", Color.SlateGray, +new Colorful.Formatter("https://github.com/2881099/FreeSql", Color.DeepSkyBlue), +new Colorful.Formatter("v" + string.Join(".", typeof(ConsoleApp).Assembly.GetName().Version.ToString().Split('.').Where((a, b) => b <= 2)), Color.SlateGray)); + + ArgsOutput = Directory.GetCurrentDirectory(); + ArgsFileName = "{name}.cs"; + string args0 = args[0].Trim().ToLower(); + if (args[0] == "?" || args0 == "--help" || args0 == "-help") + { + + Console.WriteFormatted(@" + {0} + + 更新工具:dotnet tool update -g FreeSql.Generator + + + # 快速开始 # + + > {1} {2} 1 {3} 0,0,0,0 {4} MyProject {5} ""MySql,Data Source=127.0.0.1;..."" + + -Razor 1 * 选择模板:实体类+特性 + + -Razor 2 * 选择模板:实体类+特性+导航属性 + + -Razor ""d:\diy.cshtml"" * 自定义模板文件 + + -NameOptions * 总共4个布尔值,分别对应: + # 首字母大写 + # 首字母大写,其他小写 + # 全部小写 + # 下划线转驼峰 + + -NameSpace * 命名空间 + + -DB ""{6},Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=数据库;Charset=utf8;SslMode=none;Max pool size=2"" + + -DB ""{7},Data Source=.;Integrated Security=True;Initial Catalog=数据库;Pooling=true;Max Pool Size=2"" + + -DB ""{8},Host=192.168.164.10;Port=5432;Username=postgres;Password=123456;Database=数据库;Pooling=true;Maximum Pool Size=2"" + + -DB ""{9},user id=user1;password=123456;data source=//127.0.0.1:1521/XE;Pooling=true;Max Pool Size=2"" + + -DB ""{10},Driver={DM8 ODBC DRIVER};Server=127.0.0.1:5236;Persist Security Info=False;Trusted_Connection=Yes;UID=USER1;PWD=123456789;Max pool size=2"" + {10} 是国产达梦数据库,需要使用 ODBC 连接 + + -FileName 文件名,默认:{name}.cs + + -Output 保存路径,默认为当前 shell 所在目录 + {11} + +", Color.SlateGray, +new Colorful.Formatter("使用 FreeSql 快速生成数据库的实体类", Color.SlateGray), +new Colorful.Formatter("FreeSql.Generator", Color.White), +new Colorful.Formatter("-Razor", Color.ForestGreen), +new Colorful.Formatter("-NameOptions", Color.ForestGreen), +new Colorful.Formatter("-NameSpace", Color.ForestGreen), +new Colorful.Formatter("-DB", Color.ForestGreen), +new Colorful.Formatter("MySql", Color.Yellow), +new Colorful.Formatter("SqlServer", Color.Yellow), +new Colorful.Formatter("PostgreSQL", Color.Yellow), +new Colorful.Formatter("Oracle", Color.Yellow), +new Colorful.Formatter("OdbcDameng", Color.Yellow), +new Colorful.Formatter("推荐在实体类目录创建 gen.bat,双击它重新所有实体类", Color.ForestGreen) +); + wait.Set(); + return; + } + for (int a = 0; a < args.Length; a++) + { + switch (args[a]) + { + case "-Razor": + ArgsRazorRaw = args[a + 1].Trim(); + switch (ArgsRazorRaw) + { + case "1": ArgsRazor = RazorContentManager.实体类_特性_cshtml; break; + case "2": ArgsRazor = RazorContentManager.实体类_特性_导航属性_cshtml; break; + default: ArgsRazor = File.ReadAllText(args[a + 1]); break; + } + a++; + break; + + case "-NameOptions": + ArgsNameOptions = args[a + 1].Split(',').Select(opt => opt == "1").ToArray(); + if (ArgsNameOptions.Length != 4) throw new ArgumentException("-NameOptions 参数错误,格式为:0,0,0,0"); + a++; + break; + case "-NameSpace": + ArgsNameSpace = args[a + 1]; + a++; + break; + case "-DB": + var dbargs = args[a + 1].Split(',', 2); + if (dbargs.Length != 2) throw new ArgumentException("-DB 参数错误,格式为:MySql,ConnectionString"); + switch (dbargs[0].Trim().ToLower()) + { + case "mysql": ArgsDbType = DataType.MySql; break; + case "sqlserver": ArgsDbType = DataType.SqlServer; break; + case "postgresql": ArgsDbType = DataType.PostgreSQL; break; + case "oracle": ArgsDbType = DataType.Oracle; break; + case "odbcdameng": ArgsDbType = DataType.OdbcDameng; break; + default: throw new ArgumentException($"-DB 参数错误,不支持的类型:{dbargs[0]}"); + } + ArgsConnectionString = dbargs[1].Trim(); + if (string.IsNullOrEmpty(ArgsConnectionString)) throw new ArgumentException($"-DB 参数错误,未提供 ConnectionString"); + a++; + break; + case "-FileName": + ArgsFileName = args[a + 1]; + a++; + break; + case "-Output": + ArgsOutput = args[a + 1]; + a++; + break; + } + } + + ArgsOutput = ArgsOutput.Trim().TrimEnd('/', '\\'); + ArgsOutput += ArgsOutput.Contains("\\") ? "\\" : "/"; + if (!Directory.Exists(ArgsOutput)) + Directory.CreateDirectory(ArgsOutput); + + RazorEngine.Engine.Razor = RazorEngineService.Create(new RazorEngine.Configuration.TemplateServiceConfiguration + { + EncodedStringFactory = new RazorEngine.Text.RawStringFactory() // Raw string encoding. + }); + var razorId = Guid.NewGuid().ToString("N"); + RazorEngine.Engine.Razor.Compile(ArgsRazor, razorId); + + var outputCounter = 0; + using (IFreeSql fsql = new FreeSql.FreeSqlBuilder() + .UseConnectionString(ArgsDbType, ArgsConnectionString) + .UseAutoSyncStructure(false) + .UseMonitorCommand(cmd => Console.WriteFormatted(cmd.CommandText + "\r\n", Color.SlateGray)) + .Build()) + { + var tables = fsql.DbFirst.GetTablesByDatabase(); + var outputTables = tables; + + + //开始生成操作 + foreach (var table in outputTables) + { + var sw = new StringWriter(); + var model = new RazorModel(fsql, ArgsNameSpace, ArgsNameOptions, tables, table); + RazorEngine.Engine.Razor.Run(razorId, sw, null, model); + + StringBuilder plus = new StringBuilder(); + plus.AppendLine("//------------------------------------------------------------------------------"); + plus.AppendLine("// "); + plus.AppendLine("// 此代码由工具 FreeSql.Generator 生成。"); + plus.AppendLine("// 运行时版本:" + Environment.Version.ToString()); + plus.AppendLine("// Website: https://github.com/2881099/FreeSql"); + plus.AppendLine("// 对此文件的更改可能会导致不正确的行为,并且如果"); + plus.AppendLine("// 重新生成代码,这些更改将会丢失。"); + plus.AppendLine("// "); + plus.AppendLine("//------------------------------------------------------------------------------"); + plus.Append(sw.ToString()); + plus.AppendLine(); + + var outputFile = $"{ArgsOutput}{ArgsFileName.Replace("{name}", model.GetCsName(table.Name))}"; + File.WriteAllText(outputFile, plus.ToString()); + Console.WriteFormatted(" OUT -> " + outputFile + "\r\n", Color.DeepSkyBlue); + ++outputCounter; + } + } + + var rebuildBat = ArgsOutput + "__重新生成.bat"; + if (File.Exists(rebuildBat) == false) + { + File.WriteAllText(rebuildBat, @$" +FreeSql.Generator -Razor {ArgsRazorRaw} - NameOptions {string.Join(",", ArgsNameOptions.Select(a => a ? 1 : 0))} -NameSpace {ArgsNameSpace} -DB ""{ArgsDbType},{ArgsConnectionString}"" +"); + Console.WriteFormatted(" OUT -> " + rebuildBat + " (以后) 双击它重新生成实体\r\n", Color.Magenta); + ++outputCounter; + } + + Console.WriteFormatted($"\r\n[{DateTime.Now.ToString("MM-dd HH:mm:ss")}] 生成完毕,总共生成了 {outputCounter} 个文件,目录:\"{ArgsOutput}\"\r\n", Color.DarkGreen); + + Console.ReadKey(); + wait.Set(); + } + } +} + diff --git a/Extensions/FreeSql.Generator/FreeSql.Generator.csproj b/Extensions/FreeSql.Generator/FreeSql.Generator.csproj new file mode 100644 index 00000000..a1802290 --- /dev/null +++ b/Extensions/FreeSql.Generator/FreeSql.Generator.csproj @@ -0,0 +1,33 @@ + + + + Exe + netcoreapp3.1 + true + true + true + 2881099 + 2881099 + FreeSql123 + 使用 FreeSql 快速生成数据库的实体类; dotnet tool install -g FreeSql.Generator + https://github.com/2881099/FreeSql + https://github.com/2881099/FreeSql + 0.12.16 + FreeSql DbFirst 实体生成器 + + + + + + + + + + + + + + + + + diff --git a/Extensions/FreeSql.Generator/Program.cs b/Extensions/FreeSql.Generator/Program.cs new file mode 100644 index 00000000..1b4475fe --- /dev/null +++ b/Extensions/FreeSql.Generator/Program.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace FreeSql.Generator +{ + public class Program + { + static void Main(string[] args) + { + if (args != null && args.Length == 0) args = new[] { "?" }; + ManualResetEvent wait = new ManualResetEvent(false); + new Thread(() => { + Thread.CurrentThread.Join(TimeSpan.FromSeconds(1)); + ConsoleApp app = new ConsoleApp(args, wait); + }).Start(); + wait.WaitOne(); + return; + } + } +} diff --git a/Extensions/FreeSql.Generator/RazorContentManager.cs b/Extensions/FreeSql.Generator/RazorContentManager.cs new file mode 100644 index 00000000..e46a6370 --- /dev/null +++ b/Extensions/FreeSql.Generator/RazorContentManager.cs @@ -0,0 +1,246 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace FreeSql.Generator +{ + class RazorContentManager + { + public static string 实体类_特性_cshtml = + #region 长内容 + @"@using FreeSql.DatabaseModel;@{ +var gen = Model as RazorModel; + +Func GetAttributeString = attr => { + if (string.IsNullOrEmpty(attr)) return null; + return string.Concat("", "", attr.Trim('[', ']')); +}; +Func GetDefaultValue = col => { + if (col.CsType == typeof(string)) return "" = string.Empty;""; + return """"; +}; +}@{ +switch (gen.fsql.Ado.DataType) { + case FreeSql.DataType.PostgreSQL: +@:using System; +@:using System.Collections; +@:using System.Collections.Generic; +@:using System.Linq; +@:using System.Reflection; +@:using System.Threading.Tasks; +@:using Newtonsoft.Json; +@:using FreeSql.DataAnnotations; +@:using System.Net; +@:using Newtonsoft.Json.Linq; +@:using System.Net.NetworkInformation; +@:using NpgsqlTypes; +@:using Npgsql.LegacyPostgis; + break; + case FreeSql.DataType.SqlServer: + case FreeSql.DataType.MySql: + default: +@:using System; +@:using System.Collections; +@:using System.Collections.Generic; +@:using System.Linq; +@:using System.Reflection; +@:using System.Threading.Tasks; +@:using Newtonsoft.Json; +@:using FreeSql.DataAnnotations; + break; +} +} +namespace @gen.NameSpace { + +@if (string.IsNullOrEmpty(gen.table.Comment) == false) { + @:/// + @:/// @gen.table.Comment.Replace(""\r\n"", ""\n"").Replace(""\n"", ""\r\n /// "") + @:/// +} + [JsonObject(MemberSerialization.OptIn)@GetAttributeString(gen.GetTableAttribute())] + public partial class @gen.GetCsName(gen.FullTableName) { + + @foreach (var col in gen.columns) { + + if (string.IsNullOrEmpty(col.Coment) == false) { + @:/// + @:/// @col.Coment.Replace(""\r\n"", ""\n"").Replace(""\n"", ""\r\n /// "") + @:/// + } + @:@(""[JsonProperty"" + GetAttributeString(gen.GetColumnAttribute(col)) + ""]"") + @:public @gen.GetCsType(col) @gen.GetCsName(col.Name) { get; set; }@GetDefaultValue(col) +@: + } + } +@gen.GetMySqlEnumSetDefine() +}"; + #endregion + + public static string 实体类_特性_导航属性_cshtml = + #region 长内容 + @"@using FreeSql.DatabaseModel;@{ + +var isLazying = true; //延时加载 +var isOneToMany = true; //一对多,集合属性 +var isManyToMany = true; //多对多,集合属性 + +var gen = Model as RazorModel; +var fks = gen.table.Foreigns; + +Func GetAttributeString = attr => { + if (string.IsNullOrEmpty(attr)) return null; + return string.Concat("", "", attr.Trim('[', ']')); +}; + +Func GetFkObjectName = fkx => { + var eqfks = fks.Where(fk22a => fk22a.ReferencedTable.Name == fkx.ReferencedTable.Name); + if (eqfks.Count() == 1) return fkx.ReferencedTable.Name; + var fkretname = fkx.Columns[0].Name; + if (fkretname.EndsWith(fkx.ReferencedColumns[0].Name, StringComparison.CurrentCultureIgnoreCase)) fkretname = fkretname.Substring(0, fkretname.Length - fkx.ReferencedColumns[0].Name.Length).TrimEnd('_'); + if (fkretname.EndsWith(fkx.ReferencedTable.Name, StringComparison.CurrentCultureIgnoreCase)) fkretname = fkretname.Substring(0, fkretname.Length - fkx.ReferencedTable.Name.Length).TrimEnd('_'); + if (fkretname.StartsWith(fkx.ReferencedTable.Name, StringComparison.CurrentCultureIgnoreCase)) fkretname = fkretname.Substring(fkx.ReferencedTable.Name.Length).TrimStart('_'); + return fkx.ReferencedTable.Name + (string.IsNullOrEmpty(fkretname) ? """" : (""_"" + fkretname)); +}; +Func GetFkObjectNameOutside = fkx => { + var eqfks = fkx.Table.Foreigns.Where(fk22a => fk22a.ReferencedTable.Name == fkx.ReferencedTable.Name); + if (eqfks.Count() == 1) return fkx.Table.Name; + var fkretname = fkx.Columns[0].Name; + if (fkretname.EndsWith(fkx.ReferencedColumns[0].Name, StringComparison.CurrentCultureIgnoreCase)) fkretname = fkretname.Substring(0, fkretname.Length - fkx.ReferencedColumns[0].Name.Length).TrimEnd('_'); + if (fkretname.EndsWith(fkx.ReferencedTable.Name, StringComparison.CurrentCultureIgnoreCase)) fkretname = fkretname.Substring(0, fkretname.Length - fkx.ReferencedTable.Name.Length).TrimEnd('_'); + if (fkretname.StartsWith(fkx.ReferencedTable.Name, StringComparison.CurrentCultureIgnoreCase)) fkretname = fkretname.Substring(fkx.ReferencedTable.Name.Length).TrimStart('_'); + return fkx.Table.Name + ""s""; +}; +}@{ +switch (gen.fsql.Ado.DataType) { + case FreeSql.DataType.PostgreSQL: +@:using System; +@:using System.Collections.Generic; +@:using Newtonsoft.Json; +@:using FreeSql.DataAnnotations; +@:using System.Net; +@:using Newtonsoft.Json.Linq; +@:using System.Net.NetworkInformation; +@:using NpgsqlTypes; +@:using Npgsql.LegacyPostgis; + break; + case FreeSql.DataType.SqlServer: + case FreeSql.DataType.MySql: + default: +@:using System; +@:using System.Collections.Generic; +@:using Newtonsoft.Json; +@:using FreeSql.DataAnnotations; + break; +} +} +namespace @gen.NameSpace { + +@if (string.IsNullOrEmpty(gen.table.Comment) == false) { + @:/// + @:/// @gen.table.Comment.Replace(""\r\n"", ""\n"").Replace(""\n"", ""\r\n /// "") + @:/// +} + [JsonObject(MemberSerialization.OptIn)@GetAttributeString(gen.GetTableAttribute())] + public partial class @gen.GetCsName(gen.FullTableName) { + + @foreach (var col in gen.columns) { + + var findfks = fks.Where(fkaa => fkaa.Columns.Where(fkaac1 => fkaac1.Name == col.Name).Any()); + var csname = gen.GetCsName(col.Name); + + if (string.IsNullOrEmpty(col.Coment) == false) { + @:/// + @:/// @col.Coment.Replace(""\r\n"", ""\n"").Replace(""\n"", ""\r\n /// "") + @:/// + } + @:@(""[JsonProperty"" + GetAttributeString(gen.GetColumnAttribute(col)) + ""]"") + if (findfks.Any() == false) { + @:public @gen.GetCsType(col) @csname { get; set; } + } else { + @:public @gen.GetCsType(col) @csname { get => _@csname; set { + @:if (_@csname == value) return; + @:_@csname = value; + foreach (var fkcok2 in findfks) { + @:@GetFkObjectName(fkcok2) = null; + } + @:} } + @:private @gen.GetCsType(col) _@csname; + } +@: + } +@if (fks.Any()) { +@: + @:#region 外键 => 导航属性,ManyToOne/OneToOne + foreach (var fk in fks) { + var fkTableName = (fk.ReferencedTable.Schema + ""."" + fk.ReferencedTable.Name).Trim('.'); + if (fk.ReferencedTable.Schema == ""public"" || fk.ReferencedTable.Schema == ""dbo"") + { + fkTableName = fkTableName.Replace(fk.ReferencedTable.Schema + ""."", """"); + } +@: + @:[Navigate(""@string.Join("", "", fk.Columns.Select(a => gen.GetCsName(a.Name)))"")] + @:public@(isLazying ? "" virtual"" : """") @gen.GetCsName(fkTableName) @GetFkObjectName(fk) { get; set; } + } +@: + @:#endregion +} +@if (isOneToMany && gen.tables.Where(tmpft => tmpft.Foreigns.Where(tmpftfk => tmpftfk.ReferencedTable.Schema == gen.table.Schema && tmpftfk.ReferencedTable.Name == gen.table.Name && tmpftfk.Columns.Where(tmpcol => tmpcol.IsPrimary).Count() != tmpftfk.Columns.Count).Any()).Any()) { +@: + @:#region 外键 => 导航属性,OneToMany + foreach (var ft in gen.tables) { + var ftfks = ft.Foreigns.Where(ftfk => ftfk.ReferencedTable.Schema == gen.table.Schema && ftfk.ReferencedTable.Name == gen.table.Name && ftfk.Columns.Where(tmpcol => tmpcol.IsPrimary).Count() != ftfk.Columns.Count).ToArray(); + foreach (var fk in ftfks) { + var fkTableName = (ft.Schema + ""."" + ft.Name).Trim('.'); + if (ft.Schema == ""public"" || ft.Schema == ""dbo"") + { + fkTableName = fkTableName.Replace(ft.Schema + ""."", """"); + } +@: + @:[Navigate(""@string.Join("", "", fk.Columns.Select(a => gen.GetCsName(a.Name)))"")] + @:public@(isLazying ? "" virtual"" : """") List<@gen.GetCsName(fkTableName)> @GetFkObjectNameOutside(fk)s { get; set; } + } + } +@: + @:#endregion +} +@if (isManyToMany) { +@: + @:#region 外键 => 导航属性,ManyToMany + foreach (var ft in gen.tables) { + if (ft != gen.table) { + var ftfks = ft.Foreigns.Where(ftfk => ftfk.Columns.Where(ftfkcol => ftfkcol.IsPrimary == false).Any() == false).ToArray(); + if (ftfks.Length == 2) { + var fk1 = ftfks.Where(ftfk => (ftfk.ReferencedTable.Schema + ""."" + ftfk.ReferencedTable.Name).Trim('.') == gen.FullTableName).ToArray(); + if (fk1.Length == 1) { + var fk2 = ftfks.Where(ftfk => fk1.Contains(ftfk) == false).ToArray(); + + var midft = ft; + var leftft = gen.table; + DbTableInfo rightft = null; + if (fk2.Any()) { + rightft = fk2[0].ReferencedTable; + } else { + rightft = fk1[1].ReferencedTable; + } + + var fkTableName = (rightft.Schema + ""."" + rightft.Name).Trim('.'); + if (rightft.Schema == ""public"" || rightft.Schema == ""dbo"") + { + fkTableName = fkTableName.Replace(rightft.Schema + ""."", """"); + } + var csname = rightft.Name; +@: + @:public@(isLazying ? "" virtual"" : """") List<@gen.GetCsName(fkTableName)> @gen.GetCsName(csname)s { get; set; } + } + } + } + } +@: + @:#endregion +} + } +@gen.GetMySqlEnumSetDefine() +}"; + #endregion + } +} diff --git a/Extensions/FreeSql.Generator/RazorModel.cs b/Extensions/FreeSql.Generator/RazorModel.cs new file mode 100644 index 00000000..80f7a855 --- /dev/null +++ b/Extensions/FreeSql.Generator/RazorModel.cs @@ -0,0 +1,145 @@ +using FreeSql.DatabaseModel; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +public class RazorModel { + public RazorModel(IFreeSql fsql, string nameSpace, bool[] NameOptions, List tables, DbTableInfo table) { + this.fsql = fsql; + this.NameSpace = nameSpace; + this.NameOptions = NameOptions; + this.tables = tables; + this.table = table; + } + + public IFreeSql fsql { get; set; } + public bool[] NameOptions { get; set; } + public List tables { get; set; } + public DbTableInfo table { get; set; } + public List columns => this.table.Columns; + public string NameSpace { get; set; } + public string FullTableName => $"{(new[] { "public", "dbo" }.Contains(table.Schema) ? "" : table.Schema)}.{table.Name}".TrimStart('.'); + + public string GetCsName(string name) { + name = Regex.Replace(name.TrimStart('@', '.'), @"[^\w]", "_"); + name = char.IsLetter(name, 0) ? name : string.Concat("_", name); + if (NameOptions[0]) name = UFString(name); + if (NameOptions[1]) name = UFString(name.ToLower()); + if (NameOptions[2]) name = name.ToLower(); + if (NameOptions[3]) name = string.Join("", name.Split('_').Select(a => UFString(a))); + return name; + } + public string UFString(string text) { + text = Regex.Replace(text, @"[^\w]", "_"); + if (text.Length <= 1) return text.ToUpper(); + else return text.Substring(0, 1).ToUpper() + text.Substring(1, text.Length - 1); + } + public string LFString(string text) { + text = Regex.Replace(text, @"[^\w]", "_"); + if (text.Length <= 1) return text.ToLower(); + else return text.Substring(0, 1).ToLower() + text.Substring(1, text.Length - 1); + } + + public string GetCsType(DbColumnInfo col) { + if (fsql.Ado.DataType == FreeSql.DataType.MySql) + if (col.DbType == (int)MySql.Data.MySqlClient.MySqlDbType.Enum || col.DbType == (int)MySql.Data.MySqlClient.MySqlDbType.Set) + return $"{this.GetCsName(this.FullTableName)}{this.GetCsName(col.Name).ToUpper()}{(col.IsNullable ? "?" : "")}"; + return fsql.DbFirst.GetCsType(col); + } + + #region 特性 + public string GetTableAttribute() { + var sb = new List(); + + if (GetCsName(this.FullTableName) != this.FullTableName) + sb.Add("Name = \"" + this.FullTableName + "\""); + + if (sb.Any() == false) return null; + return "[Table(" + string.Join(", ", sb) + ")]"; + } + public string GetColumnAttribute(DbColumnInfo col) { + var sb = new List(); + + if (GetCsName(col.Name) != col.Name) + sb.Add("Name = \"" + col.Name + "\""); + + var dbinfo = fsql.CodeFirst.GetDbInfo(col.CsType); + if (dbinfo != null && dbinfo.Value.dbtypeFull.Replace("NOT NULL", "").Trim() != col.DbTypeTextFull) + sb.Add("DbType = \"" + col.DbTypeTextFull + "\""); + if (col.IsPrimary) + sb.Add("IsPrimary = true"); + if (col.IsIdentity) + sb.Add("IsIdentity = true"); + + if (dbinfo != null && dbinfo.Value.isnullable != col.IsNullable) { + if (col.IsNullable && fsql.DbFirst.GetCsType(col).Contains("?") == false && col.CsType.IsValueType) + sb.Add("IsNullable = true"); + if (col.IsNullable == false && fsql.DbFirst.GetCsType(col).Contains("?") == true) + sb.Add("IsNullable = false"); + } + if (sb.Any() == false) return null; + return "[Column(" + string.Join(", ", sb) + ")]"; + } + #endregion + + #region mysql enum/set + public string GetMySqlEnumSetDefine() { + if (fsql.Ado.DataType != FreeSql.DataType.MySql) return null; + var sb = new StringBuilder(); + foreach (var col in table.Columns) { + if (col.DbType == (int)MySql.Data.MySqlClient.MySqlDbType.Enum || col.DbType == (int)MySql.Data.MySqlClient.MySqlDbType.Set) { + if (col.DbType == (int)MySql.Data.MySqlClient.MySqlDbType.Set) sb.Append("\r\n\t[Flags]"); + sb.Append($"\r\n\tpublic enum {this.GetCsName(this.FullTableName)}{this.GetCsName(col.Name).ToUpper()}"); + if (col.DbType == (int)MySql.Data.MySqlClient.MySqlDbType.Set) sb.Append(" : long"); + sb.Append(" {\r\n\t\t"); + + string slkdgjlksdjg = ""; + int field_idx = 0; + int unknow_idx = 0; + string exp2 = string.Concat(col.DbTypeTextFull); + int quote_pos = -1; + while (true) { + int first_pos = quote_pos = exp2.IndexOf('\'', quote_pos + 1); + if (quote_pos == -1) break; + while (true) { + quote_pos = exp2.IndexOf('\'', quote_pos + 1); + if (quote_pos == -1) break; + int r_cout = 0; + //for (int p = 1; true; p++) { + // if (exp2[quote_pos - p] == '\\') r_cout++; + // else break; + //} + while (exp2[++quote_pos] == '\'') r_cout++; + if (r_cout % 2 == 0/* && quote_pos - first_pos > 2*/) { + string str2 = exp2.Substring(first_pos + 1, quote_pos - first_pos - 2).Replace("''", "'"); + if (Regex.IsMatch(str2, @"^[\u0391-\uFFE5a-zA-Z_\$][\u0391-\uFFE5a-zA-Z_\$\d]*$")) + slkdgjlksdjg += ", " + str2; + else + slkdgjlksdjg += string.Format(@", +/// +/// {0} +/// +[Description(""{0}"")] +Unknow{1}", str2.Replace("\"", "\\\""), ++unknow_idx); + if (col.DbType == (int)MySql.Data.MySqlClient.MySqlDbType.Set) + slkdgjlksdjg += " = " + Math.Pow(2, field_idx++); + if (col.DbType == (int)MySql.Data.MySqlClient.MySqlDbType.Enum && field_idx++ == 0) + slkdgjlksdjg += " = 1"; + break; + } + } + if (quote_pos == -1) break; + } + sb.Append(slkdgjlksdjg.Substring(2).TrimStart('\r', '\n', '\t')); + sb.Append("\r\n\t}"); + } + } + return sb.ToString(); + } + #endregion +} + + diff --git a/FreeSql.sln b/FreeSql.sln index 3464c254..b5273404 100644 --- a/FreeSql.sln +++ b/FreeSql.sln @@ -66,6 +66,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Tests.Provider.Odbc EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "orm_vs_net40", "Examples\orm_vs_net40\orm_vs_net40.csproj", "{1674BCE3-EEB4-4003-A2A7-06F51EFAEA23}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Generator", "Extensions\FreeSql.Generator\FreeSql.Generator.csproj", "{6A3A4470-7DF7-411B-AAD7-755D7A9DB5A4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -388,6 +390,18 @@ Global {1674BCE3-EEB4-4003-A2A7-06F51EFAEA23}.Release|x64.Build.0 = Release|Any CPU {1674BCE3-EEB4-4003-A2A7-06F51EFAEA23}.Release|x86.ActiveCfg = Release|Any CPU {1674BCE3-EEB4-4003-A2A7-06F51EFAEA23}.Release|x86.Build.0 = Release|Any CPU + {6A3A4470-7DF7-411B-AAD7-755D7A9DB5A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6A3A4470-7DF7-411B-AAD7-755D7A9DB5A4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6A3A4470-7DF7-411B-AAD7-755D7A9DB5A4}.Debug|x64.ActiveCfg = Debug|Any CPU + {6A3A4470-7DF7-411B-AAD7-755D7A9DB5A4}.Debug|x64.Build.0 = Debug|Any CPU + {6A3A4470-7DF7-411B-AAD7-755D7A9DB5A4}.Debug|x86.ActiveCfg = Debug|Any CPU + {6A3A4470-7DF7-411B-AAD7-755D7A9DB5A4}.Debug|x86.Build.0 = Debug|Any CPU + {6A3A4470-7DF7-411B-AAD7-755D7A9DB5A4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6A3A4470-7DF7-411B-AAD7-755D7A9DB5A4}.Release|Any CPU.Build.0 = Release|Any CPU + {6A3A4470-7DF7-411B-AAD7-755D7A9DB5A4}.Release|x64.ActiveCfg = Release|Any CPU + {6A3A4470-7DF7-411B-AAD7-755D7A9DB5A4}.Release|x64.Build.0 = Release|Any CPU + {6A3A4470-7DF7-411B-AAD7-755D7A9DB5A4}.Release|x86.ActiveCfg = Release|Any CPU + {6A3A4470-7DF7-411B-AAD7-755D7A9DB5A4}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -411,6 +425,7 @@ Global {3043DEF1-85DF-47AD-8D5D-327270794356} = {4A92E8A6-9A6D-41A1-9CDA-DE10899648AA} {C57444BA-8BF7-4790-A864-7F237123219B} = {2A381C57-2697-427B-9F10-55DA11FD02E4} {1674BCE3-EEB4-4003-A2A7-06F51EFAEA23} = {94C8A78D-AA15-47B2-A348-530CD86BFC1B} + {6A3A4470-7DF7-411B-AAD7-755D7A9DB5A4} = {4A92E8A6-9A6D-41A1-9CDA-DE10899648AA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {089687FD-5D25-40AB-BA8A-A10D1E137F98} diff --git a/readme.md b/readme.md index 5bc30cc7..473aecee 100644 --- a/readme.md +++ b/readme.md @@ -9,7 +9,7 @@ FreeSql 是功能强大的对象关系映射技术(O/RM),支持 .NETCore 2.1+ # Features - [x] 支持 CodeFirst 迁移; -- [x] 支持 DbFirst 从数据库导入实体类; +- [x] 支持 DbFirst 从数据库导入实体类,[安装实体类生成工具](https://github.com/2881099/FreeSql/wiki/DbFirst); - [x] 大量采用 ExpressionTree 提升性能; - [x] 支持 深入的类型映射,比如pgsql的数组类型; - [x] 支持 丰富的表达式函数; @@ -43,12 +43,6 @@ FreeSql 是功能强大的对象关系映射技术(O/RM),支持 .NETCore 2.1+ - 要么[FreeSql.Connection.Extensions](https://github.com/2881099/FreeSql.Connection.Extensions),有点像Dapper的使用习惯; - 要么[BaseEntity](https://github.com/2881099/FreeSql/tree/master/Examples/base_entity),我求简单现在使用的这个; -> 其他下载 - -- [FreeSql.Tools 生成器](https://github.com/2881099/FreeSql.Tools),基于 razor 模板的生成器; -- [Abp 中使用 FreeSql](https://github.com/gnsilence/JPGZService),测试中...; -- [FreeSql 优势.pptx](https://github.com/2881099/FreeSql/files/3305852/FreeSql.pptx); - > 学习项目 - [😃 A simple and practical CMS implememted by .NET Core 2.2](https://github.com/luoyunchong/lin-cms-dotnetcore)