diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..6573f368 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.js linguist-language=c# diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..29f81d81 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index 234bff14..60961fb9 100644 --- a/README.md +++ b/README.md @@ -1 +1,65 @@ -一款支持exe和web的代码管理 生成器 ,还在开发中敬请期待 +## 框架描述 +WebFirst 是果糖大数据团队开发的新一代 高性能 代码生成器&数据库设计工具,由.net core + sqlsugar 开发 导入1000个表只要1-2秒,用法简单,功能强大,支持多种数据库 +### 图片预览 + +![输入图片说明](https://www.donet5.com//_theme/ueditor/utf8-net/net/upload/image/20211009/6376941449795119979562201.png "用例") + +### 功能预览 + +1、 建库、CodeFirst方式在线建表,没用到CodeFirst的用户可以用工具轻松体验,支持公共字段 + +2、导出EXCEL文档,把每个表的数据导出来 + +3、模版管理 可以自个添加修改模版,使用的是Razor模版引擎对C#程序员更加友好 + +4、方案管理,可以创建自已的生成方案,修改方案 + +5、支持扩展模版属性,支持生成更加丰富的前端代码 + +6、支持生成解决方案 + +7、支持生成附加文件,支持文件后缀 + +8、支持视图 + +9、支持自定义数据类型 + +10、支持多种数据库 MYSQL PGSQL SQLITE SQLSERVE ORCLE 达梦 + +### 功能特色 +1、生成器与你具体的项目解耦,可以独立管理多个解决方案 + +2、支持一键生成多个解决方案 + +3、支持EXE方式和Web方式部署 + +## 使用场景 + +1、提高工作效率 + +我们都知道一个CRUD其实如果有代码生成器的话只需要几分钟就可以把完整的功能做完,如果用手去写那么可能就要花掉一整天的时间,多出来的这些时间学学技术多好 + +2、大量重复有共性的功能 + +使用代码生成器最重要的就是减少大量重复的工作,比如我们有 数据库model 有表单model 有Grid绑定的 model 光写这些MODEL就很头痛,要写各种特性 + +## 使用教程 +### 配置实体 +1、通过数据库导入实体: 菜单【配置实体(表建类模式)】 + +2、在线建实体 : 菜单【配置实体(类建表模式)】 + +3、通过SQL建实体: 菜单【配置实体(视图模式)】 +### 一键生成 +配置实体后就可以使用自带的一键生成功能来生成用例代码,通过自带方案和模版的配置可以快速了解框架 +### 方案管理 +一键生成可以生成多个方案,方案 包含: 模版、路径、文件名、文件后缀 等 可以理解为某个模版的生成配置 +### 模版管理 +模版是方案的一个重要参数,什么样的模版 生成什么样的文件内容,比如 实体类就编写实体类模版 ,业务就编写业务模版 + + +## 下载软件 +[WebFirst最新版本下载](https://www.donet5.com/Doc/11/2388) + +## QQ群交流 +QQ交流群: 958343000 diff --git a/SoEasyPlatform.sln b/SoEasyPlatform.sln index 5c8e535b..48f17d2a 100644 --- a/SoEasyPlatform.sln +++ b/SoEasyPlatform.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30523.141 +# Visual Studio Version 17 +VisualStudioVersion = 17.1.32414.318 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SoEasyPlatform", "SoEasyPlatform\SoEasyPlatform.csproj", "{D4E4101E-81B5-40F8-903D-D6E069250841}" EndProject diff --git a/SoEasyPlatform/Apis/CodeTableApp/CodeTableController.cs b/SoEasyPlatform/Apis/CodeTableApp/CodeTableController.cs new file mode 100644 index 00000000..4dc18189 --- /dev/null +++ b/SoEasyPlatform/Apis/CodeTableApp/CodeTableController.cs @@ -0,0 +1,809 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using AutoMapper; +using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json.Linq; +using SqlSugar; + +namespace SoEasyPlatform.Apis +{ + /// + /// 虚拟类配置 + /// + [Route("api/[controller]")] + [ApiController] + public partial class CodeTableController : BaseController + { + IMapper _mapper; + public CodeTableController(IMapper mapper) : base(mapper) + { + _mapper = mapper; + } + + #region CodeTable CRUD + /// + /// 生成表根据视图 + /// + /// + /// + [HttpPost] + [ExceptionFilter] + [Route("CreateTableByView")] + public ActionResult> CreateTableByView([FromForm] string ViewSql, [FromForm] int dbid, [FromForm] string className) + { + ApiResult result = new ApiResult() { IsSuccess = true }; + var tableDb = base.GetTryDb(dbid); + var dt = tableDb.Ado.GetDataTable(ViewSql); + base.Check(dt.Rows.Count == 0, "SQL查询必须要有一条记录才能创建类"); + CodeTable table = new CodeTable() + { + TableName = className, + CreateTime = DateTime.Now, + ClassName = className, + IsLock = true, + DbId = dbid, + UpdateTime = DateTime.Now, + Description = "数据源导入" + }; + var id = Db.Insertable(table).ExecuteReturnIdentity(); + List cols = new List(); + var listtypes = CodeTypeDb.GetList(); + foreach (System.Data.DataColumn item in dt.Columns) + { + CodeColumns columns = new CodeColumns() + { + CodeTableId = id, + ClassProperName = item.ColumnName, + DbColumnName = item.ColumnName, + CodeType = listtypes.FirstOrDefault(it => it.CSharepType.Equals(item.DataType.Name, StringComparison.OrdinalIgnoreCase) || it.DbType.Any(y => y.Name.Equals(item.DataType.Name, StringComparison.OrdinalIgnoreCase)))?.Name + }; + if (item.DataType.Name.ToLower() == "int32") + { + columns.CodeType = listtypes.Where(it => it.CSharepType == "int").First().Name; + } + if (item.DataType.Name.ToLower() == "int16") + { + columns.CodeType = listtypes.Where(it => it.CSharepType == "short").First().Name; + } + if (item.DataType.Name.ToLower() == "int64") + { + columns.CodeType = listtypes.Where(it => it.CSharepType == "long").First().Name; + } + if (string.IsNullOrEmpty(columns.CodeType)) + { + columns.CodeType = listtypes.Where(it => it.CSharepType == "string").First().Name; + } + cols.Add(columns); + } + Db.Insertable(cols).ExecuteReturnIdentity(); + result.IsSuccess = true; + result.Data = result.Message = "创建成功"; + return result; + } + /// + /// 获取虚拟类 + /// + /// + [HttpPost] + [Route("GetCodeTableList")] + public ActionResult>> GetCodeTableList([FromForm] CodeTableViewModel model) + { + var result = new ApiResult>(); + result.Data = new TableModel(); + int count = 0; + var list = Db.Queryable( + (it, db) => new JoinQueryInfos( + JoinType.Left, it.DbId == db.Id + ) + ) + .Where(it => it.DbId == model.DbId) + .WhereIF(!string.IsNullOrEmpty(model.ClassName), it => it.ClassName.Contains(model.ClassName) || it.TableName.Contains(model.ClassName)) + .OrderBy(it => it.TableName) + .Select((it, db) => new CodeTableGridViewModel() + { + Id = it.Id.SelectAll(), + DbName = db.Desc + }) + .ToPageList(model.PageIndex, int.MaxValue, ref count) + .OrderBy(it => it.CreateTime.AddSeconds(100) >= DateTime.Now ? 0 : 1).ToList(); + result.Data.Rows = list; + result.Data.Total = count; + result.Data.PageSize = count; + result.Data.PageNumber = model.PageIndex; + result.IsSuccess = true; + return result; + } + + + /// + /// 获取虚拟类根据主键 + /// + /// + [HttpPost] + [Route("GetCodeTableInfo")] + public ActionResult> GetCodeTableInfo([FromForm] string id) + { + var result = new ApiResult(); + result.Data = mapper.Map(base.CodeTableDb.GetById(id)); + result.Data.ColumnInfoList = mapper.Map>(base.CodeColumnsDb.GetList(it => it.CodeTableId == Convert.ToInt32(id))); + result.IsSuccess = true; + return result; + } + + /// + /// 保存虚拟类 + /// + /// + /// + [HttpPost] + [FormValidateFilter] + [ExceptionFilter] + [Route("SaveCodeTable")] + public ActionResult> SaveCodeTable([FromForm] string model) + { + var result = new ApiResult(); + CodeTableViewModel viewModel = Newtonsoft.Json.JsonConvert.DeserializeObject(model); + viewModel.CreateTime = DateTime.Now; + SaveCodeTableToDb(viewModel); + result.IsSuccess = true; + return result; + } + + + /// + /// 删除虚拟类 + /// + /// + [HttpPost] + [Route("DeleteCodeTable")] + public ActionResult> DeleteCodeTable([FromForm] string model) + { + var result = new ApiResult(); + if (!string.IsNullOrEmpty(model)) + { + var list = Newtonsoft.Json.JsonConvert.DeserializeObject>(model); + Db.Utilities.PageEach(list, 50, eitem => + { + var exp = Expressionable.Create(); + foreach (var item in eitem) + { + exp.Or(it => it.Id == item.Id); + } + CodeTableDb.Update(it => new CodeTable() { IsDeleted = true }, exp.ToExpression()); + }); + } + result.IsSuccess = true; + return result; + } + + #endregion + + #region Code Type CRUD + + /// + /// 获取类型 + /// + /// + [HttpPost] + [Route("GetCodeTypeList")] + public ActionResult>> GetCodeTypeList([FromForm] CodeTypeViewModel model) + { + model.PageSize = 20; + var result = new ApiResult>(); + result.Data = new TableModel(); + int count = 0; + var list = CodeTypeDb.AsSugarClient().Queryable() + .WhereIF(!string.IsNullOrEmpty(model.Name), it => it.Name.Contains(model.Name) || it.CSharepType.Contains(model.Name)) + .OrderBy(it => it.Sort) + .OrderBy(it => it.Id) + .ToPageList(model.PageIndex, model.PageSize, ref count); + var codeGridList = mapper.Map>(list); + foreach (var item in codeGridList) + { + var dbType = list.First(it => it.Id == item.Id).DbType; + item.DbType = Newtonsoft.Json.JsonConvert.SerializeObject(dbType); + } + result.Data.Rows = codeGridList; + result.Data.Total = count; + result.Data.PageSize = model.PageSize; + result.Data.PageNumber = model.PageIndex; + result.IsSuccess = true; + return result; + } + + /// + /// 添加类型 + /// + /// + [HttpPost] + [FormValidateFilter] + [Route("SaveCodeType")] + public ActionResult> SaveCodeType([FromForm] CodeTypeViewModel model) + { + var result = new ApiResult(); + JsonResult errorResult = base.ValidateModel(model.Id); + if (errorResult != null) return errorResult; + CodeType codetype = new CodeType() + { + Id =Convert.ToInt32(model.Id), + CSharepType = model.CSharepType, + Name = model.Name, + Sort = model.Sort.Value + }; + try + { + codetype.DbType = Newtonsoft.Json.JsonConvert.DeserializeObject(model.DbType); + } + catch + { + result.IsSuccess = false; + result.Data = model.DbType + "格式不正确"; + return result; + } + var x = Db.Storageable(codetype).ToStorage(); + x.AsUpdateable.ExecuteCommand(); + x.AsInsertable.ExecuteCommand(); + result.IsSuccess = true; + result.Data =x.InsertList.Any()? Pubconst.MESSAGEADDSUCCESS:Pubconst.MESSAGESAVESUCCESS; + return result; + } + #endregion + + #region Create File + /// + /// 创建方案 + /// + /// + [HttpPost] + [FormValidateFilter] + [ExceptionFilter] + [Route("createfile")] + public ActionResult> CreateFile([FromForm] ProjectViewModel model) + { + base.Check(model.Reference != null && model.Reference.Split(',').Contains(model.Id + ""), "方案不能自已引用自已"); + base.Check(new System.IO.DirectoryInfo(model.Path)?.Parent?.Parent == null, "路径" + model.Path + "错误,正确格式 C:\\解决方案\\项目"); + var result = new ApiResult(); + var tempInfo = TemplateDb.GetById(model.TemplateId1); + model.ModelId = tempInfo.TemplateTypeId; + var dbModel = mapper.Map(model); + var s = base.Db.Storageable(dbModel) + .SplitError(it => string.IsNullOrEmpty(model.Tables), "请选择表") + .SplitError(it => Db.Queryable().Any(s => s.Id != model.Id && s.ProjentName == model.ProjentName && s.TemplateId1 == model.TemplateId1), "方前方案已存在请换个名字或者使用方案生成") + .Saveable() + .ToStorage(); + var id = s.AsInsertable.ExecuteReturnIdentity(); + s.AsUpdateable.ExecuteCommand(); + if (s.ErrorList.Any()) + { + throw new Exception(s.ErrorList.First().StorageMessage); + } + //var template = TemplateDb.GetById(model.TemplateId1).Content; + //var tableids = Newtonsoft.Json.JsonConvert.DeserializeObject>(model.Tables).Select(it => it.Id).ToList(); + //var tableList = CodeTableDb.GetList(it => tableids.Contains(it.Id)); + //int dbId = tableList.First().DbId; + //var connection = base.GetTryDb(dbId); + //List genList = GetGenList(tableList, CodeTypeDb.GetList(), connection.CurrentConnectionConfig.DbType); + //string key = TemplateHelper.EntityKey + template.GetHashCode(); + //foreach (var item in genList) + //{ + // item.name_space = GetNameSpace(model.FileModel,item.name_space); + // var html = TemplateHelper.GetTemplateValue(key, template, item); + // var fileName = GetFileName(model, item); + // FileSugar.CreateFileReplace(fileName, html, Encoding.UTF8); + //} + //ProjectController_Common.CreateProject(dbModel); + result.IsSuccess = true; + result.Message = model.Id == 0 ? "创建成功" : "修改成功"; + return result; + } + + /// + /// 生成实体 + /// + /// + [HttpPost] + [FormValidateFilter] + [ExceptionFilter] + [Route("CreateFileByProjectId")] + public ActionResult> CreateFileByProjectId([FromForm] ProjectViewModel2 model, bool disOpen = true) + { + var result = new ApiResult(); + var tables = model.Tables; + var project = ProjectDb.GetSingle(it => it.Id == model.ProjectId); + base.Check(project == null, "请选择方案"); + model.Tables = tables; + var template = TemplateDb.GetById(project.TemplateId1).Content; + var tableids = Newtonsoft.Json.JsonConvert.DeserializeObject>(model.Tables).Select(it => it.Id).ToList(); + var tableList = CodeTableDb.GetList(it => tableids.Contains(it.Id)); + int dbId = tableList.First().DbId; + var connection = base.GetTryDb(dbId); + List genList = GetGenList(tableList, CodeTypeDb.GetList(), connection.CurrentConnectionConfig.DbType); + string key = TemplateHelper.EntityKey + template.GetHashCode(); + foreach (var item in genList) + { + item.name_space = GetNameSpace(project.FileModel, item.name_space); + var html = TemplateHelper.GetTemplateValue(key, template, item); + var fileName = GetFileName(project, item); + FileSugar.CreateFileReplace(fileName, html, Encoding.UTF8); + } + OpenPath(disOpen, project); + ProjectController_Common.CreateProject(project.Id, model.DbId.Value); + result.IsSuccess = true; + result.Message = "生成生功"; + return result; + } + #endregion + + #region Export + /// + ////导出文档 + /// + /// + [HttpPost] + [ExceptionFilter] + [Route("exportfile")] + public ApiResult Exportfile([FromForm] string model, [FromForm] int dbid) + { + ApiResult result = new ApiResult() { IsSuccess = true }; + var tableDb = base.GetTryDb(dbid); + var dts = Export(model, tableDb); + var bytes = Table_ToExcel.ExportExcel(dts, "数据库文档.xlsx"); + var url = FileSugar.MergeUrl(Startup.CurrentDirectory, "excel/数据库文档" + SqlSugar.SnowFlakeSingle.Instance.getID() + ".xlsx"); + FileSugar.CreateFile(url, bytes); + OpenPath(url); + return result; + } + #endregion + + #region CreateTable + /// + ////生成表 + /// + /// + [HttpPost] + [ExceptionFilter] + [Route("CreateTables")] + public ActionResult> CreateTables([FromForm] string model, [FromForm] int dbid) + { + var tableDb = base.GetTryDb(dbid); + var result = new ApiResult(); + if (!string.IsNullOrEmpty(model)) + { + var list = Newtonsoft.Json.JsonConvert.DeserializeObject>(model); + var oldList = CodeTableDb.AsQueryable().In(list.Select(it => it.Id).ToList()).ToList(); + base.Check(oldList.Any(it => it.IsLock), string.Join(",", oldList.Where(it => it.IsLock).Select(it => it.ClassName)) + "是锁表状态禁止建表"); + List genList = GetGenList(oldList, CodeTypeDb.GetList(), tableDb.CurrentConnectionConfig.DbType); + foreach (var item in genList) + { + item.PropertyGens = item.PropertyGens.Where(it => it.IsIgnore == false).ToList(); + foreach (var property in item.PropertyGens) + { + if (property.IsSpecialType) + { + property.Type = "string"; + } + } + } + string key = TemplateHelper.EntityKey + SyntaxTreeHelper.TemplateString.GetHashCode(); + foreach (var item in genList) + { + var classString = TemplateHelper.GetTemplateValue(key, SyntaxTreeHelper.TemplateString, item); + var type = SyntaxTreeHelper.GetModelTypeByClass(classString, item.ClassName); + tableDb.CurrentConnectionConfig.ConfigureExternalServices = new ConfigureExternalServices() { + EntityNameService = (type, info) => + { + if (info.EntityName == item.ClassName || (info.EntityName == null && info.DbTableName == item.ClassName)) + { + info.EntityName = item.ClassName; + info.DbTableName = item.TableName; + info.TableDescription = item.Description; + } + }, + EntityService = (type, info) => + { + if (info.EntityName == item.ClassName) + { + var column = item.PropertyGens.FirstOrDefault(it => it.PropertyName == info.PropertyName); + info.DbColumnName = column.DbColumnName; + info.ColumnDescription = column.Description; + info.IsNullable = column.IsNullable; + info.Length = Convert.ToInt32(column.Length); + info.DecimalDigits = Convert.ToInt32(column.DecimalDigits); + info.IsPrimarykey = column.IsPrimaryKey; + info.IsIdentity = column.IsIdentity; + info.IsIgnore = column.IsIgnore; + info.DataType = column.DbType; + if (tableDb.CurrentConnectionConfig.DbType == DbType.Sqlite && info.IsIdentity) + { + info.DataType = "integer"; + } + } + } + }; + tableDb.CodeFirst.InitTables(type); + } + + } + result.IsSuccess = true; + return result; + } + + + + /// + ////结构对比 + /// + /// + [HttpPost] + [ExceptionFilter] + [Route("GetTableDiff")] + public ActionResult> GetTableDiff([FromForm] string model, [FromForm] int dbid) + { + var tableDb = base.GetTryDb(dbid); + var result = new ApiResult(); + List tableDifferences = new List(); + if (!string.IsNullOrEmpty(model)) + { + var list = Newtonsoft.Json.JsonConvert.DeserializeObject>(model); + var oldList = CodeTableDb.AsQueryable().In(list.Select(it => it.Id).ToList()).ToList(); + base.Check(oldList.Any(it => it.IsLock), string.Join(",", oldList.Where(it => it.IsLock).Select(it => it.ClassName)) + "是锁表状态禁止建表"); + List genList = GetGenList(oldList, CodeTypeDb.GetList(), tableDb.CurrentConnectionConfig.DbType); + foreach (var item in genList) + { + item.PropertyGens = item.PropertyGens.Where(it => it.IsIgnore == false).ToList(); + foreach (var property in item.PropertyGens) + { + if (property.IsSpecialType) + { + property.Type = "string"; + } + } + } + string key = TemplateHelper.EntityKey + SyntaxTreeHelper.TemplateString.GetHashCode(); + foreach (var item in genList) + { + var classString = TemplateHelper.GetTemplateValue(key, SyntaxTreeHelper.TemplateString, item); + var type = SyntaxTreeHelper.GetModelTypeByClass(classString, item.ClassName); + tableDb.CurrentConnectionConfig.ConfigureExternalServices = new ConfigureExternalServices() + { + EntityNameService = (type, info) => + { + if (info.EntityName == item.ClassName || (info.EntityName == null && info.DbTableName == item.ClassName)) + { + info.EntityName = item.ClassName; + info.DbTableName = item.TableName; + info.TableDescription = item.Description; + } + }, + EntityService = (type, info) => + { + if (info.EntityName == item.ClassName) + { + var column = item.PropertyGens.FirstOrDefault(it => it.PropertyName == info.PropertyName); + info.DbColumnName = column.DbColumnName; + info.ColumnDescription = column.Description; + info.IsNullable = column.IsNullable; + info.Length = Convert.ToInt32(column.Length); + info.DecimalDigits = Convert.ToInt32(column.DecimalDigits); + info.IsPrimarykey = column.IsPrimaryKey; + info.IsIdentity = column.IsIdentity; + info.IsIgnore = column.IsIgnore; + info.DataType = column.DbType; + if (tableDb.CurrentConnectionConfig.DbType == DbType.Sqlite && info.IsIdentity) + { + info.DataType = "integer"; + } + } + } + }; + if(tableDb.DbMaintenance.IsAnyTable(item.TableName, false)) + { + var diff = tableDb.CodeFirst.GetDifferenceTables(type).ToDiffString(); + if (diff != null && !diff.Contains("No change")) + { + tableDifferences.Add(diff); + } + } + } + + } + if (tableDifferences.Count == 0) + { + result.Data = "此操作没有风险,可以继续!!"; + } + else + { + result.Data = string.Join("", tableDifferences).Replace("\n","
"); + } + result.Data = result.Data.Replace( "
----", "

"); + result.Data = result.Data.Replace("----", "

"); + result.Data = result.Data.Replace("Table:", "表名:"); + result.Data = result.Data.Replace("Add column", "添加列"); + result.Data = result.Data.Replace("Update column", "更新列"); + result.Data = result.Data.Replace("Delete column", "删除列"); + result.IsSuccess = true; + return result; + } + #endregion + + #region Update entity by db + /// + /// 从数据库导入虚拟类 + /// + /// + /// + [HttpPost] + [FormValidateFilter] + [ExceptionFilter] + [Route("savecodetableimport")] + public ActionResult> SaveCodetableImport([FromForm] int dbid, [FromForm] string model) + { + ApiResult result = new ApiResult(); + var list = Newtonsoft.Json.JsonConvert.DeserializeObject>(model); + var tableDb = base.GetTryDb(dbid); + var systemDb = Db; + var type = CodeTypeDb.GetList(); + var entityList = CodeTableDb.GetList(it => it.DbId == dbid); + systemDb.BeginTran(); + try + { + List Inserts = new List(); + foreach (var item in list) + { + CodeTableViewModel code = new CodeTableViewModel() + { + ClassName = PubMehtod.GetCsharpName(item.Name), + TableName = item.Name, + DbId = dbid, + Description = item.Description, + ColumnInfoList = new List() + }; + var entity = entityList.FirstOrDefault(it => it.TableName.Equals(item.Name, StringComparison.OrdinalIgnoreCase)); + if (entity == null) + { + entity = new CodeTable(); + } + foreach (var columnInfo in tableDb.DbMaintenance.GetColumnInfosByTableName(item.Name, false)) + { + var typeInfo = GetEntityType(type, columnInfo, this, tableDb.CurrentConnectionConfig.DbType); + CodeColumnsViewModel column = new CodeColumnsViewModel() + { + ClassProperName = PubMehtod.GetCsharpName(columnInfo.DbColumnName), + DbColumnName = columnInfo.DbColumnName, + Description = columnInfo.ColumnDescription, + IsIdentity = columnInfo.IsIdentity, + IsPrimaryKey = columnInfo.IsPrimarykey, + Required = columnInfo.IsNullable == false, + CodeTableId = entity.Id, + CodeType = typeInfo.CodeType.Name, + Length = typeInfo.DbTypeInfo.Length, + DecimalDigits = typeInfo.DbTypeInfo.DecimalDigits, + DefaultValue = columnInfo.DefaultValue + }; + code.ColumnInfoList.Add(column); + } + SaveCodeTableToDb(code); + }; + systemDb.CommitTran(); + result.IsSuccess = true; + } + catch (Exception ex) + { + systemDb.RollbackTran(); + throw ex; + } + return result; + } + + /// + ////根据数据库更新虚拟类 + /// + /// + [HttpPost] + [ExceptionFilter] + [Route("UpdateEntity")] + public ActionResult> UpdateEntity([FromForm] string model, [FromForm] int dbid) + { + var tableDb = base.GetTryDb(dbid); + var result = new ApiResult(); + if (!string.IsNullOrEmpty(model)) + { + var list = Newtonsoft.Json.JsonConvert.DeserializeObject>(model); + Db.Utilities.PageEach(list, 20, pageList => + { + UpdateEntityItem(dbid, tableDb, pageList); + }); + } + result.IsSuccess = true; + return result; + } + + private void UpdateEntityItem(int dbid, SqlSugarClient tableDb, List list) + { + var oldList = CodeTableDb.AsQueryable().In(list.Select(it => it.Id).ToList()).ToList(); + var oldColumns = Db.Queryable((c, t) => c.CodeTableId == t.Id).Where((c, t) => oldList.Select(it => it.Id).Contains(t.Id)).Select((c, t) => new { TableId = t.Id, TableName = t.TableName, Columns = c }).ToList(); + var alltables = tableDb.DbMaintenance.GetTableInfoList(false).Select(it => it.Name.ToLower()).ToList(); + var ids = list.Select(it => it.Id).ToList(); + var tableNames = list.Select(it => it.TableName.ToLower()).ToList(); + var errorTables = list.Where(it => !alltables.Contains(it.TableName.ToLower()) && !alltables.Contains(it.ClassName.ToLower())).ToList(); + base.Check(errorTables.Any(), string.Join(",", errorTables.Select(y => y.TableName ?? y.ClassName)) + "未创建表不能同步"); + try + { + Db.BeginTran(); + CodeTableDb.DeleteByIds(ids.Select(it => (object)it).ToArray()); + var dbTableGridList = tableDb.DbMaintenance.GetTableInfoList(false).Where(it => tableNames.Contains(it.Name.ToLower())).Select(it => new DbTableGridViewModel() + { + Description = it.Description, + Name = it.Name + }); + if (dbTableGridList.Any()) + { + SaveCodetableImport(dbid, Newtonsoft.Json.JsonConvert.SerializeObject(dbTableGridList)); + } + foreach (var item in oldList) + { + CodeTableDb.AsUpdateable(item).UpdateColumns(it => it.ClassName).WhereColumns(it => it.TableName).ExecuteCommand(); + } + List UpdateColumns = new List(); + foreach (var item in oldColumns.GroupBy(it => new { it.TableId, it.TableName }).ToList()) + { + var tableId = CodeTableDb.AsQueryable().Where(it => it.TableName == item.Key.TableName && it.DbId == dbid).First()?.Id; + if (tableId != null) + { + var columns = CodeColumnsDb.AsQueryable().Where(it => it.CodeTableId == tableId).ToList(); + foreach (var col in columns) + { + var addColumn = item.FirstOrDefault(it => it.Columns.DbColumnName == col.DbColumnName); + if (addColumn != null) + { + col.ClassProperName = addColumn.Columns.ClassProperName; + UpdateColumns.Add(col); + } + else + { + + } + } + foreach (var oldItem in item.ToList()) + { + if (oldItem.Columns.CodeType.Equals("ignore", StringComparison.CurrentCultureIgnoreCase)) + { + var mapp = _mapper.Map(oldItem.Columns); + mapp.CodeTableId = columns[0].CodeTableId; + CodeColumnsDb.AsInsertable(mapp).ExecuteCommand(); + } + } + } + } + CodeColumnsDb.AsUpdateable(UpdateColumns).UpdateColumns(it => it.ClassProperName).ExecuteCommand(); + Db.CommitTran(); + } + catch (Exception ex) + { + Db.RollbackTran(); + throw ex; + } + } + + + #endregion + + #region Copy + /// + /// 复制 + /// + /// + [HttpPost] + [FormValidateFilter] + [ExceptionFilter] + [Route("Copy")] + public ActionResult> Copy([FromForm] ProjectViewModel2 model) + { + var result = new ApiResult(); + var tables = model.Tables; + var project = ProjectDb.GetSingle(it => it.Id == model.ProjectId); + base.Check(project == null, "请选择方案,没有方案可以在手动生成里面创建"); + model.Tables = tables; + var template = TemplateDb.GetById(project.TemplateId1).Content; + var tableids = Newtonsoft.Json.JsonConvert.DeserializeObject>(model.Tables).Select(it => it.Id).ToList(); + var tableList = CodeTableDb.GetList(it => tableids.Contains(it.Id)); + int dbId = tableList.First().DbId; + var connection = base.GetTryDb(dbId); + List genList = GetGenList(tableList, CodeTypeDb.GetList(), connection.CurrentConnectionConfig.DbType); + string key = TemplateHelper.EntityKey + template.GetHashCode(); + foreach (var item in genList.Take(1)) + { + item.name_space = GetNameSpace(project.FileModel, item.name_space); + result.Data = TemplateHelper.GetTemplateValue(key, template, item); + } + ProjectController_Common.CreateProject(project.Id, model.DbId.Value); + result.IsSuccess = true; + return result; + } + #endregion + + #region Append Field + /// + /// 追加字段 + /// + /// + [HttpPost] + [FormValidateFilter] + [ExceptionFilter] + [Route("SaveCommField")] + public ActionResult> SaveCommField([FromForm] string Field,[FromForm] string model,[FromForm] int? dbid) + { + ApiResult result = new ApiResult(); + var fields = (Field+"").Split(',').Where(it=>!string.IsNullOrEmpty(it)).ToList(); + var fieldInfoList = CommonFieldDb.GetList(it => fields.Contains(it.Id.ToString())); + var list = Newtonsoft.Json.JsonConvert.DeserializeObject>(model); + List addcolumns = new List(); + foreach (var item in list) + { + var columns = CodeColumnsDb.GetList(it => it.CodeTableId == item.Id); + + foreach (var filedItem in fieldInfoList) + { + if (!columns.Any(y=>y.DbColumnName.ToLower() == filedItem.DbColumnName.ToLower())&& !columns.Any(y => y.ClassProperName.ToLower() == filedItem.ClassProperName.ToLower())) + { + if (!addcolumns.Any(it => it.DbColumnName == filedItem.DbColumnName && it.CodeTableId == Convert.ToInt32(item.Id))) + { + addcolumns.Add(new CodeColumns() + { + CodeTableId = Convert.ToInt32(item.Id), + DbColumnName = filedItem.DbColumnName, + ClassProperName = filedItem.ClassProperName, + CodeType = CodeTypeDb.GetById(filedItem.CodeType).Name, + IsIdentity = filedItem.IsIdentity, + IsPrimaryKey = filedItem.IsPrimaryKey, + Required = filedItem.Required, + Description= filedItem.Description + }); + } + } + } + } + CodeColumnsDb.InsertRange(addcolumns); + result.IsSuccess = true; + result.Data = "追加成功"; + return result; + } + + #endregion + + #region Append Property + /// + /// 追加属性 + /// + /// + [HttpPost] + [ExceptionFilter] + [Route("SaveTagProperty")] + public ActionResult> SaveTagProperty([FromForm] string model, [FromForm] int? dbid = 0) + { + dynamic json = JObject.Parse(model); + string table = json.table.Value ; + Db.Deleteable().Where(it => it.DbId == dbid.Value && it.TableName == table).ExecuteCommand(); + foreach (var item in json.columns) + { + var key = item.key.Value; + var value = item.value; + if (value.Count > 0) + { + foreach (var tag in value) + { + + Db.Insertable(new MappingProperty() { DbId = dbid.Value, TableName = table, ColumnName = key, TagId= tag.Value }).ExecuteCommand(); + } + } + } + ApiResult result = new ApiResult() { IsSuccess = true }; + return result; + } + #endregion + } +} diff --git a/SoEasyPlatform/Apis/CodeTableApp/CodeTableController_CreateFile.cs b/SoEasyPlatform/Apis/CodeTableApp/CodeTableController_CreateFile.cs new file mode 100644 index 00000000..896999eb --- /dev/null +++ b/SoEasyPlatform/Apis/CodeTableApp/CodeTableController_CreateFile.cs @@ -0,0 +1,247 @@ +using AutoMapper; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace SoEasyPlatform.Apis +{ + /// + /// 创建文件接口相关业务 + /// + public partial class CodeTableController : BaseController + { + /// + /// 打开目录 + /// + /// + /// + private static void OpenPath(bool disOpen, Project project) + { + if (disOpen) + { + Task.Run(() => + { + try + { + System.Diagnostics.Process.Start("explorer.exe",new System.IO.DirectoryInfo(project.Path).Parent.FullName); + } + catch + { + + } + }); + } + } + /// + /// 打开目录 + /// + /// + /// + private static void OpenPath(string path) + { + try + { + System.Diagnostics.Process.Start("explorer.exe", new System.IO.DirectoryInfo(path).Parent.FullName); + } + catch + { + + } + } + private List GetGenList(List tableList, List types,SqlSugar.DbType databasedbType) + { + List result = new List(); + var mapping = Db.Queryable().ToList(); + var tags = Db.Queryable().ToList(); + if (databasedbType == DbType.MySql) + { + var timestamp = types.FirstOrDefault(it => it.Name == "timestamp"); + if (timestamp != null) + { + timestamp.CSharepType = "DateTime"; + } + } + foreach (var item in tableList) + { + EntitiesGen gen = new EntitiesGen() + { + ClassName = item.ClassName, + Description = item.Description, + TableName = item.TableName, + PropertyGens = new List() + }; + foreach (var column in base.CodeColumnsDb.GetList(it => it.CodeTableId == item.Id)) + { + var codeType = types.First(it => it.Name == column.CodeType); + if (codeType.Id == 3) + { + PropertyGen proGen = new PropertyGen() + { + DbColumnName = column.DbColumnName, + Description = column.Description, + IsIdentity = column.IsIdentity, + IsPrimaryKey = column.IsPrimaryKey, + PropertyName = GetPropertyName(column.ClassProperName), + Type = GetType(column), + IsNullable = column.Required == false, + DbType ="", + Length = 0, + DecimalDigits = 0, + IsIgnore = true, + CodeType=column.CodeType, + DefaultValue=column.DefaultValue + }; + var mappings= mapping.Where(it => item.DbId == it.DbId && it.TableName == item.ClassName && it.ColumnName == column.ClassProperName).ToList(); ; + proGen.MappingProperties = tags.Where(it => mappings.Any(x => x.TagId == it.Id + "")).ToList(); + gen.PropertyGens.Add(proGen); + } + else + { + var dbType = GetTypeInfoByDatabaseType(codeType.DbType, databasedbType); + PropertyGen proGen = new PropertyGen() + { + DbColumnName = column.DbColumnName, + Description = column.Description, + IsIdentity = column.IsIdentity, + IsPrimaryKey = column.IsPrimaryKey, + PropertyName = GetPropertyName(column.ClassProperName), + Type = IsSpecialType(column) ? GetType(column) : codeType.CSharepType, + IsNullable = column.Required == false, + DbType = dbType.Name, + Length = dbType.Length, + DecimalDigits = dbType.DecimalDigits, + IsSpecialType= IsSpecialType(column), + CodeType= column.CodeType, + DefaultValue=column.DefaultValue + }; + var mappings = mapping.Where(it => item.DbId == it.DbId && it.TableName == item.ClassName && it.ColumnName == column.ClassProperName).ToList(); ; + proGen.MappingProperties = tags.Where(it => mappings.Any(x => x.TagId == it.Id + "")).ToList(); + gen.PropertyGens.Add(proGen); + } + } + result.Add(gen); + } + return result; + } + + private static bool IsSpecialType(CodeColumns column) + { + return Regex.IsMatch(column.ClassProperName, @"\[.+\]"); + } + + private static string GetType(CodeColumns column) + { + string type = "string"; + if (IsSpecialType(column)) + { + type = Regex.Match(column.ClassProperName, @"\[(.+)\]").Groups[1].Value; + } + + return type; + } + + private static string GetPropertyName(string name) + { + return Regex.Replace(name, @"\[(.+)\]", ""); + } + + private DbTypeInfo GetTypeInfoByDatabaseType(DbTypeInfo[] dbType, DbType databasedbType) + { + DbTypeInfo result = dbType.First(); + List mstypes = new List(); + switch (databasedbType) + { + case DbType.MySql: + mstypes = SqlSugar.MySqlDbBind.MappingTypesConst.Select(it => it.Key.ToLower()).ToList(); + break; + case DbType.SqlServer: + mstypes= SqlSugar.SqlServerDbBind.MappingTypesConst.Select(it => it.Key.ToLower()).ToList(); + break; + case DbType.Sqlite: + mstypes = SqlSugar.SqliteDbBind.MappingTypesConst.Select(it => it.Key.ToLower()).ToList(); + break; + case DbType.Oracle: + mstypes = SqlSugar.OracleDbBind.MappingTypesConst.Select(it => it.Key.ToLower()).ToList(); + break; + case DbType.PostgreSQL: + if (dbType.Any(it => it.Name == "blob")) + { + var list = new List { new DbTypeInfo() { Name = "bit" } }; + list.AddRange(dbType); + dbType = list.ToArray(); + } + mstypes = SqlSugar.PostgreSQLDbBind.MappingTypesConst.Select(it => it.Key.ToLower()).ToList(); + break; + case DbType.Dm: + mstypes = SqlSugar.DmDbBind.MappingTypesConst.Select(it => it.Key.ToLower()).ToList(); + break; + case DbType.Kdbndp: + mstypes = SqlSugar.KdbndpDbBind.MappingTypesConst.Select(it => it.Key.ToLower()).ToList(); + break; + default: + break; + } + result = dbType.FirstOrDefault(it => mstypes.Contains(it.Name.ToLower())); + if (result == null) + { + throw new Exception("WebFirst暂时不支持类型" + string.Join(",",dbType.Select(it => it.Name))); + } + return result; + } + + private string GetFileName(ProjectViewModel project, EntitiesGen item) + { + var p = "."; + project.FileSuffix = project.FileSuffix.TrimStart('.'); + if (project.FileSuffix.Contains(".")) + { + p = null; + } + return FileSugar.MergeUrl(project.Path, item.ClassName + p + project.FileSuffix); + } + + private string GetFileName(Project project, EntitiesGen item) + { + var p = "."; + string name = item.ClassName; + project.FileSuffix = project.FileSuffix.TrimStart('.'); + if (project.FileSuffix.Contains(".")) + { + p = null; + } + if (project.NameFormat != null && project.NameFormat.Contains("@(") && project.NameFormat.Contains(")")) + { + var format = project.NameFormat.Replace("{0}", "Model.ClassName"); + name = TemplateHelper.GetTemplateValue(project.NameFormat + "format", format, item); + } + else if (!string.IsNullOrEmpty(project.NameFormat)) + { + name = string.Format(project.NameFormat, item.ClassName); + } + return FileSugar.MergeUrl(project.Path, name + p + project.FileSuffix); + } + private string GetNameSpace(string fileModel, string defaultvalue) + { + if (!string.IsNullOrEmpty(fileModel)) + { + dynamic obj = Newtonsoft.Json.JsonConvert.DeserializeObject(fileModel); + try + { + return obj[0].name; + } + catch + { + return defaultvalue; + } + } + else + { + return defaultvalue; + } + } + } +} diff --git a/SoEasyPlatform/Apis/CodeTableApp/CodeTableController_Export.cs b/SoEasyPlatform/Apis/CodeTableApp/CodeTableController_Export.cs new file mode 100644 index 00000000..cdf78bd5 --- /dev/null +++ b/SoEasyPlatform/Apis/CodeTableApp/CodeTableController_Export.cs @@ -0,0 +1,62 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Threading.Tasks; + +namespace SoEasyPlatform.Apis +{ + /// + /// 数据库导入虚拟类相关逻辑 + /// + public partial class CodeTableController : BaseController + { + + private DataTable [] Export(string model, SqlSugarClient tableDb) + { + var list = Newtonsoft.Json.JsonConvert.DeserializeObject>(model); + var oldList = CodeTableDb.AsQueryable().In(list.Select(it => it.Id).ToList()).ToList(); + List genList = GetGenList(oldList, CodeTypeDb.GetList(), tableDb.CurrentConnectionConfig.DbType); + List datatables = new List(); + foreach (var item in genList) + { + DataTable dt = new DataTable(); + dt.Columns.Add("列名"); + dt.Columns.Add("列描述"); + dt.Columns.Add("列类型"); + dt.Columns.Add("实体类型"); + dt.Columns.Add("主键"); + dt.Columns.Add("自增"); + dt.Columns.Add("可空"); + dt.Columns.Add("长度"); + dt.Columns.Add("精度"); + dt.Columns.Add("默认值"); + dt.Columns.Add("表名"); ; + dt.Columns.Add("表描述"); + foreach (var it in item.PropertyGens) + { + var dr = dt.NewRow(); + dr["列名"] = it.DbColumnName; + dr["列描述"] = it.Description; + dr["列类型"] = it.DbType; + dr["实体类型"] = it.Type; + dr["表名"] = item.TableName; ; + dr["表描述"] = item.Description; + + dr["主键"] = it.IsPrimaryKey?"是":""; + dr["自增"] = it.IsIdentity ? "是" : ""; + dr["可空"] = it.IsNullable ? "是" : ""; + dr["长度"] = it.Length; + dr["精度"] = it.DecimalDigits; + dr["默认值"] = it.DefaultValue; + + dt.Rows.Add(dr); + } + dt.TableName = item.TableName; + datatables.Add(dt); + } + return datatables.ToArray(); + } + } +} diff --git a/SoEasyPlatform/Code/Apis/CodeTableControllerBiz.cs b/SoEasyPlatform/Apis/CodeTableApp/CodeTableController_SaveCodeTableToDb.cs similarity index 60% rename from SoEasyPlatform/Code/Apis/CodeTableControllerBiz.cs rename to SoEasyPlatform/Apis/CodeTableApp/CodeTableController_SaveCodeTableToDb.cs index 07e87b26..7e14d8d7 100644 --- a/SoEasyPlatform/Code/Apis/CodeTableControllerBiz.cs +++ b/SoEasyPlatform/Apis/CodeTableApp/CodeTableController_SaveCodeTableToDb.cs @@ -7,13 +7,24 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; -namespace SoEasyPlatform.Code.Apis +namespace SoEasyPlatform.Apis { - + /// + /// 保存虚拟类到数据库相关逻辑 + /// public partial class CodeTableController : BaseController { private void SaveCodeTableToDb(CodeTableViewModel viewModel) { + if (!string.IsNullOrEmpty(viewModel.TableName)) + { + viewModel.TableName = viewModel.TableName.Trim(); + } + if (!string.IsNullOrEmpty(viewModel.ClassName)) + { + viewModel.ClassName = viewModel.ClassName.Trim(); + } + base.Check(string.IsNullOrEmpty(viewModel.TableName) || string.IsNullOrEmpty(viewModel.ClassName), "表名或者实体类名必须填一个"); viewModel.ColumnInfoList = viewModel.ColumnInfoList .Where(it => !string.IsNullOrEmpty(it.ClassProperName) || !string.IsNullOrEmpty(it.DbColumnName)).ToList(); @@ -22,6 +33,10 @@ private void SaveCodeTableToDb(CodeTableViewModel viewModel) AutoFillTable(dbTable); var dbColumns = mapper.Map>(viewModel.ColumnInfoList); AutoFillColumns(dbColumns); + if (dbColumns.Where(it=>!string.IsNullOrEmpty(it.DbColumnName)).GroupBy(it => it.DbColumnName.ToLower()).Any(it => it.Count() > 1)) + { + base.Check(true, "存在重复列不能保存"); + } if (viewModel.Id == null || viewModel.Id == 0) { CheckAddName(viewModel, CodeTableDb); @@ -29,6 +44,7 @@ private void SaveCodeTableToDb(CodeTableViewModel viewModel) foreach (var item in dbColumns) { item.CodeTableId = id; + item.DbColumnName = GetColumnName(item.DbColumnName); } CodeColumnsDb.InsertRange(dbColumns); } @@ -39,6 +55,7 @@ private void SaveCodeTableToDb(CodeTableViewModel viewModel) foreach (var item in dbColumns) { item.CodeTableId = dbTable.Id; + item.DbColumnName = GetColumnName(item.DbColumnName); } var oldIds = CodeColumnsDb.GetList(it => it.CodeTableId == dbTable.Id).Select(it => it.Id).ToList(); @@ -60,6 +77,17 @@ private void SaveCodeTableToDb(CodeTableViewModel viewModel) } } + private string GetColumnName(string dbColumnName) + { + if (dbColumnName == null) + return null; + if (Regex.IsMatch(dbColumnName, @"\[.+\]")) + { + return Regex.Replace(dbColumnName, @"\[.+\]",""); + } + return dbColumnName; + } + private void AutoFillTable(CodeTable dbTable) { if (string.IsNullOrEmpty(dbTable.TableName)) @@ -83,13 +111,21 @@ private void AutoFillColumns(List dbColumns) { item.DbColumnName = item.ClassProperName; } + if (!string.IsNullOrEmpty(item.ClassProperName)) + { + item.ClassProperName = item.ClassProperName.Trim(); + } + if (!string.IsNullOrEmpty(item.DbColumnName)) + { + item.DbColumnName = item.DbColumnName.Trim(); + } } } private void CheckAddName(CodeTableViewModel viewModel, Repository codeTableDb) { CheckClassName(viewModel); - var isAny = codeTableDb.IsAny(it => it.TableName == viewModel.TableName && it.IsDeleted == false); + var isAny = codeTableDb.IsAny(it => it.TableName == viewModel.TableName && it.IsDeleted == false&&(viewModel.DbId.Value==0||viewModel.DbId==it.DbId)); if (isAny) { throw new Exception(viewModel.TableName + "表名已存在"); @@ -98,7 +134,7 @@ private void CheckAddName(CodeTableViewModel viewModel, Repository co private void CheckUpdateName(CodeTableViewModel viewModel, Repository codeTableDb) { CheckClassName(viewModel); - var isAny = codeTableDb.IsAny(it => it.TableName == viewModel.TableName && it.IsDeleted == false && it.Id != viewModel.Id); + var isAny = codeTableDb.IsAny(it => it.TableName == viewModel.TableName && it.IsDeleted == false && it.Id != viewModel.Id&&(viewModel.DbId==it.DbId||viewModel.DbId.Value==0)); if (isAny) { throw new Exception(viewModel.TableName + "表名已存在"); @@ -113,89 +149,10 @@ private void CheckClassName(CodeTableViewModel viewModel) } } - private string GetEntityType(List types, DbColumnInfo columnInfo, CodeTableController codeTableController) - { - var typeInfo = types.FirstOrDefault(y => y.DbType.Any(it => it.Name.Equals(columnInfo.DataType, StringComparison.OrdinalIgnoreCase))); - if (typeInfo == null) - { - return "string100"; - } - else - { - return typeInfo.Name; - } - } - private List GetGenList(List tableList,List types) - { - List result = new List(); - foreach (var item in tableList) - { - EntitiesGen gen = new EntitiesGen() - { - ClassName = item.ClassName, - Description = item.Description, - TableName = item.TableName, - PropertyGens = new List() - }; - foreach (var column in base.CodeColumnsDb.GetList(it => it.CodeTableId == item.Id)) - { - PropertyGen proGen = new PropertyGen() - { - DbColumnName = column.DbColumnName, - Description = column.Description, - IsIdentity = column.IsIdentity, - IsPrimaryKey = column.IsPrimaryKey, - PropertyName = column.ClassProperName, - Type= types.First(it=>it.Name==column.CodeType).CSharepType, - IsNullable=column.Required==false - }; - gen.PropertyGens.Add(proGen); - } - result.Add(gen); - } - return result; - } - private string GetFileName(ProjectViewModel project, EntitiesGen item) - { - var p = "."; - project.FileSuffix = project.FileSuffix.TrimStart('.'); - if (project.FileSuffix.Contains(".")) - { - p = null; - } - return FileSugar.MergeUrl(project.Path, item.ClassName + p + project.FileSuffix ); - } - private string GetFileName(Project project, EntitiesGen item) - { - var p = "."; - project.FileSuffix = project.FileSuffix.TrimStart('.'); - if (project.FileSuffix.Contains(".")) - { - p = null; - } - return FileSugar.MergeUrl(project.Path, item.ClassName + p + project.FileSuffix); - } - private string GetNameSpace(string fileModel,string defaultvalue) - { - if (!string.IsNullOrEmpty(fileModel)) - { - dynamic obj = Newtonsoft.Json.JsonConvert.DeserializeObject(fileModel); - try - { - return obj[0].name; - } - catch - { - return defaultvalue; - } - } - else - { - return defaultvalue; - } - } + + } diff --git a/SoEasyPlatform/Apis/CodeTableApp/CodeTableController_SaveCodetableImport.cs b/SoEasyPlatform/Apis/CodeTableApp/CodeTableController_SaveCodetableImport.cs new file mode 100644 index 00000000..abe5e61d --- /dev/null +++ b/SoEasyPlatform/Apis/CodeTableApp/CodeTableController_SaveCodetableImport.cs @@ -0,0 +1,133 @@ +using AutoMapper; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace SoEasyPlatform.Apis +{ + /// + /// 数据库导入虚拟类相关逻辑 + /// + public partial class CodeTableController : BaseController + { + private SortTypeInfo GetEntityType(List types, DbColumnInfo columnInfo, CodeTableController codeTableController,DbType dbtype) + { + var typeInfo = types.FirstOrDefault(y => y.DbType.Any(it => it.Name.Equals(columnInfo.DataType, StringComparison.OrdinalIgnoreCase))); + if(typeInfo == null && columnInfo.DataType == "Double") + { + var type = types.First(it => it.Name == "decimal_18_4"); + return new SortTypeInfo() { CodeType = type, DbTypeInfo = type.DbType[0] }; + } + else if (typeInfo == null) + { + var type = types.First(it => it.Name == "string100"); + return new SortTypeInfo() { CodeType = type, DbTypeInfo = type.DbType[0] }; + } + else if (columnInfo.DataType == "json") + { + var type = types.First(it => it.Name.ToLower() == "string2000"); + return new SortTypeInfo() { CodeType = type, DbTypeInfo = type.DbType[0] }; + } + else if (columnInfo.DataType == "timestamp"&&dbtype!=DbType.SqlServer) + { + var type = types.First(it => it.Name.ToLower() == "datetime"); + return new SortTypeInfo() { CodeType = type, DbTypeInfo = type.DbType[0] }; + } + else + { + List SortTypeInfoList = new List(); + foreach (var type in types) + { + foreach (var cstype in type.DbType) + { + SortTypeInfo item = new SortTypeInfo(); + item.DbTypeInfo = cstype; + item.CodeType = type; + item.Sort = GetSort(cstype, type, columnInfo, dbtype); + SortTypeInfoList.Add(item); + } + } + var result = SortTypeInfoList.Where(it => it.CodeType.Name != "json_default").OrderByDescending(it => it.Sort).FirstOrDefault(); + if (result == null) + { + throw new Exception($"没有匹配到类型{columnInfo.DataType} 来自 {columnInfo.TableName} 表 {columnInfo.DbColumnName} ,请到类型管理添加"); + } + if (result.CodeType.Name == "guid" && columnInfo.DataType == "char" && columnInfo.Length != 36) + { + result = SortTypeInfoList.FirstOrDefault(it => it.CodeType.Name == "string100"); + } + if (dbtype == DbType.PostgreSQL) + { + if (columnInfo.DataType == "bit") + { + var type = types.First(it => it.Name.ToLower() == "bytearray"); + return new SortTypeInfo() { CodeType = type, DbTypeInfo = type.DbType[0] }; + } + } + return result; + } + } + /// + /// 匹配出最符合的类型 + /// + /// + /// + /// + /// + /// + private decimal GetSort(DbTypeInfo cstype, CodeType type, DbColumnInfo columnInfo, DbType dbtype) + { + decimal result = 0; + if (columnInfo.DataType.Equals(cstype.Name,StringComparison.OrdinalIgnoreCase)) + { + result = result + 10000; + } + else + { + result = result - 30000; + } + if (columnInfo.Length ==Convert.ToInt32(cstype.Length) ) + { + result = result + 5000; + } + else if (columnInfo.Length > Convert.ToInt32(cstype.Length)) + { + result = result+(columnInfo.Length- Convert.ToInt32(cstype.Length))*-3; + } + else + { + result = result - 500; + } + if (columnInfo.DecimalDigits == Convert.ToInt32(cstype.DecimalDigits)) + { + result = result +5000; + } + else if (columnInfo.DecimalDigits > Convert.ToInt32(cstype.DecimalDigits)) + { + result = result + (columnInfo.DecimalDigits - Convert.ToInt32(cstype.DecimalDigits)) * -3; + } + else + { + result = result - 500; + } + if (type.Name.Contains("nString") && columnInfo.DataType == "varchar") + { + result = result - 500; + } + return result; + } + /// + /// 排序计算MODEL + /// + public class SortTypeInfo + { + public DbTypeInfo DbTypeInfo { get; set; } + public decimal Sort { get; set; } + public CodeType CodeType { get; set; } + } + } +} diff --git a/SoEasyPlatform/Apis/CommonFieldApp/CommonFieldController.cs b/SoEasyPlatform/Apis/CommonFieldApp/CommonFieldController.cs new file mode 100644 index 00000000..0be51f6b --- /dev/null +++ b/SoEasyPlatform/Apis/CommonFieldApp/CommonFieldController.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using AutoMapper; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; + +namespace SoEasyPlatform.Apis +{ + [Route("api/[controller]")] + [ExceptionFilter] + [ApiController] + public class CommonFieldController : BaseController + { + + public CommonFieldController(IMapper mapper) : base(mapper) + { + } + /// + /// 获取所有公共字段 + /// + /// + [HttpPost] + [Route("GetCommonFieldList")] + public ActionResult>> GetCommonFieldList([FromForm] CommonFieldViewModel model) + { + var result = new ApiResult>(); + result.Data = new TableModel(); + int count = 0; + var list = CommonFieldDb.AsQueryable() + .ToPageList(model.PageIndex, model.PageSize, ref count); + result.Data.Rows = mapper.Map>(list); + result.Data.Total = count; + result.Data.PageSize = model.PageSize; + result.Data.PageNumber = model.PageIndex; + result.IsSuccess = true; + return result; + } + + /// + /// 保存 + /// + /// + [HttpPost] + [FormValidateFilter] + [Route("SaveCommonField")] + public ActionResult> SaveCommonField([FromForm] CommonFieldViewModel model) + { + if (string.IsNullOrEmpty(model.DbColumnName)) + { + model.DbColumnName = model.ClassProperName; + } + JsonResult errorResult = base.ValidateModel(model.Id); + if (errorResult != null) return errorResult; + var saveObject = base.mapper.Map(model); + var result = new ApiResult(); + var s = Db.Storageable(saveObject).ToStorage(); + s.AsUpdateable.ExecuteCommand(); + s.AsInsertable.ExecuteCommand(); + result.IsSuccess = s.ErrorList.Count == 0; + result.Data = result.IsSuccess ? "保存成功" : s.ErrorList.First().StorageMessage; + return result; + } + + /// + /// 删除 + /// + /// + [HttpPost] + [Route("deleteCommonField")] + public ActionResult> DeleteCommonField([FromForm] string model) + { + var result = new ApiResult(); + if (!string.IsNullOrEmpty(model)) + { + var list = Newtonsoft.Json.JsonConvert.DeserializeObject>(model); + // var isInit = Db.Queryable().In(list.Select(it=>it.Id).ToList()).Any(it => it.IsInit == true); + // base.Check(isInit, "无法删除初始化数据"); + var exp = Expressionable.Create(); + foreach (var item in list) + { + exp.Or(it => it.Id == item.Id); + } + CommonFieldDb.Update(it => new CommonField() { IsDeleted = true }, exp.ToExpression()); + } + result.IsSuccess = true; + return result; + } + } +} + diff --git a/SoEasyPlatform/Code/Apis/DatabaseController.cs b/SoEasyPlatform/Apis/DatabaseApp/DatabaseController.cs similarity index 95% rename from SoEasyPlatform/Code/Apis/DatabaseController.cs rename to SoEasyPlatform/Apis/DatabaseApp/DatabaseController.cs index c5c1d4b9..c72b5987 100644 --- a/SoEasyPlatform/Code/Apis/DatabaseController.cs +++ b/SoEasyPlatform/Apis/DatabaseApp/DatabaseController.cs @@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Mvc; using SqlSugar; -namespace SoEasyPlatform.Code.Apis +namespace SoEasyPlatform.Apis { /// /// 数据库管理 @@ -74,11 +74,12 @@ public ActionResult> SaveDatabase([FromForm] DatabaseViewModel if (errorResult != null) return errorResult; var saveObject = base.mapper.Map(model); var result = new ApiResult(); + int dbid = 0; if (saveObject.Id == 0) { saveObject.ChangeTime = DateTime.Now; saveObject.IsDeleted = false; - databaseDb.Insert(saveObject); + dbid= databaseDb.InsertReturnIdentity(saveObject); result.IsSuccess = true; result.Data = Pubconst.MESSAGEADDSUCCESS; } @@ -87,9 +88,11 @@ public ActionResult> SaveDatabase([FromForm] DatabaseViewModel saveObject.ChangeTime = DateTime.Now; saveObject.IsDeleted = false; databaseDb.Update(saveObject); + dbid = saveObject.Id; result.IsSuccess = true; result.Data = Pubconst.MESSAGEADDSUCCESS; } + base.CreateDatebase(dbid); return result; } diff --git a/SoEasyPlatform/Code/Apis/DbTableController.cs b/SoEasyPlatform/Apis/DbTableApp/DbTableController.cs similarity index 89% rename from SoEasyPlatform/Code/Apis/DbTableController.cs rename to SoEasyPlatform/Apis/DbTableApp/DbTableController.cs index 0c597d57..aab20482 100644 --- a/SoEasyPlatform/Code/Apis/DbTableController.cs +++ b/SoEasyPlatform/Apis/DbTableApp/DbTableController.cs @@ -5,7 +5,7 @@ using AutoMapper; using Microsoft.AspNetCore.Mvc; using SqlSugar; -namespace SoEasyPlatform.Code.Apis +namespace SoEasyPlatform.Apis { /// /// 数据库表操作 @@ -24,8 +24,8 @@ public ActionResult>> GetTableList(in var result =new ApiResult>(); result.Data = new TableModel(); var db = GetTryDb(dbId.Value); - result.Data.Rows=mapper.Map> (db.DbMaintenance.GetTableInfoList()); - var codetable = CodeTableDb.GetList(it => it.DbId == dbId.Value); + result.Data.Rows=mapper.Map> (db.DbMaintenance.GetTableInfoList(false)); + var codetable = CodeTableDb.AsQueryable().Where(it => it.DbId == dbId.Value).OrderBy(it=>it.TableName).ToList(); foreach (var item in result.Data.Rows) { item.IsImport = codetable.Any(it => it.TableName.Equals(item.Name, StringComparison.CurrentCultureIgnoreCase)) ? "导入" : ""; diff --git a/SoEasyPlatform/Code/Apis/FileInfoController.cs b/SoEasyPlatform/Apis/FileInfoApp/FileInfoController.cs similarity index 99% rename from SoEasyPlatform/Code/Apis/FileInfoController.cs rename to SoEasyPlatform/Apis/FileInfoApp/FileInfoController.cs index a06b35a3..af704337 100644 --- a/SoEasyPlatform/Code/Apis/FileInfoController.cs +++ b/SoEasyPlatform/Apis/FileInfoApp/FileInfoController.cs @@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Mvc; using SqlSugar; -namespace SoEasyPlatform.Code.Apis +namespace SoEasyPlatform.Apis { [Route("api/[controller]")] [ExceptionFilter] diff --git a/SoEasyPlatform/Code/Apis/ProjectController.cs b/SoEasyPlatform/Apis/ProjectApp/ProjectController.cs similarity index 83% rename from SoEasyPlatform/Code/Apis/ProjectController.cs rename to SoEasyPlatform/Apis/ProjectApp/ProjectController.cs index e074dd40..6e35245c 100644 --- a/SoEasyPlatform/Code/Apis/ProjectController.cs +++ b/SoEasyPlatform/Apis/ProjectApp/ProjectController.cs @@ -7,9 +7,10 @@ using System.Linq; using System.Threading.Tasks; -namespace SoEasyPlatform.Code.Apis +namespace SoEasyPlatform.Apis { [Route("api/[controller]")] + [ExceptionFilter] [ApiController] public class ProjectController : BaseController { @@ -41,7 +42,9 @@ public ActionResult>> GetProjectList( Path=it.Path, ProjentName=it.ProjentName, TemplateId1=it.TemplateId1.GetConfigValue