using DocumentFormat.OpenXml.Drawing.Charts; using Microsoft.AspNetCore.Mvc; using NPOI.SS.Formula.Functions; using Sarand.BusinessMgr.Net.Standard.Base.Bus.Control; using Sarand.BusinessMgr.Net.Standard.Dbas.Consoles; using Sarand.BusinessMgr.Web.Control.Components; using Sarand.BusinessMgr.Web.Control.Consoles; using Sarand.BusinessMgr.Web.Control.Models.Instance; using Sarand.Net.Standard.Base.App; using Sarand.Net.Standard.Base.Bus; using Sarand.Net.Standard.Base.Core; using Sarand.Net.Standard.Base.Dbas; using Sarand.Net.Standard.Base.Utils; using Sarand.Net.Standard.Dbas.Base; using System; using System.Collections.Generic; using System.Linq; namespace Sarand.BusinessMgr.Web.Control.Controllers.Instance { //======================================================================= partial class RepositoryDatabaseController { //------------------------------------------------------------------- // Definitions. // Core Database Table list data. private class TableListData : AjaxResponse_Data.ItemData_Base { public String SchemaName { get; set; } public String TableName { get; set; } public long? ColumnCount { get; set; } public long? IndexCount { get; set; } public long? RowCount { get; set; } } //------------------------------------------------------------------- // Get Core Database Table list ajax request. //------------------------------------------------------------------- private class AjaxResponse_RepositoryTableList : AjaxResponse_Data { // Construction. public AjaxResponse_RepositoryTableList(SbmModel_Control model) : base(model) { } // Table list. public List Tables { get; } = new List(); } //------------------------------------------------------------------- [HttpPost] [Route("Instance/Repository/Ajax/GetTableList")] [Route("Instance/Repository/Ajax/GetTables")] public IActionResult Ajax_GetTableList(Model_RepositoryDatabase model) { String messageTitle = Localiser["label.database"]; AjaxResponse_RepositoryTableList responseData = new AjaxResponse_RepositoryTableList(model); // Validate session and referrer. if (!ValidReferer) return Forbid(); if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData); RefreshModel(model); // Record disposable items as they are created so all can be disposed when needed. using (DisposableCollection disposables = new DisposableCollection()) { // Validate Repository. SessionData_Control.Profile.Filter.RepositoryContext = model.DatabaseFilter.Context; if (StringUtil.IsBlank(model.DatabaseFilter.Context)) { SaLogger.Warn($"{SysUtil.Fn} Repository Context not supplied."); return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"])); } SbmcRepository repository = ControlInstanceMgr.GetRepositoryByContext(model.DatabaseFilter.Context); if (repository == null) { SaLogger.Warn($"{SysUtil.Fn} Repository does not exist. Context: {model.DatabaseFilter.Context}."); return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"])); } // Repository Console. SbmCoreInstanceConsole_Control instanceConsole = new SbmCoreInstanceConsole_Control(SessionData_Control, repository); disposables.Add(instanceConsole); // Columns. String colSchemaName = "SchemaName"; String colTableName = "TableName"; String colColumnCount = "ColumnCount"; String colIndexCount = "IndexCount"; String colRowCount = "RowCount"; // Table filter. List filter = new List(); if (!StringUtil.IsBlank(model.DatabaseFilter.Search)) filter.Add($"tbl.name Like '%{DbQuery.FormatForLike(model.DatabaseFilter.Search)}%'"); if (!filter.Any()) filter.Add("1=1"); // Construction query. List sql = new List() { $"Select Top 2000", $"[{colSchemaName}]=sch.name, [{colTableName}]=tbl.name,", $"[{colColumnCount}]=(Select Count(*) From sys.columns col Where col.object_id=tbl.object_id),", $"[{colIndexCount}]=(Select Count(*) From sys.indexes idx Where idx.object_id=tbl.object_id),", $"[{colRowCount}]=(Select Sum(ptn.rows) From sys.partitions ptn Where ptn.object_id=tbl.object_id And ptn.index_id<2)", $"From sys.tables tbl", $"Left Join sys.schemas sch On sch.schema_id=tbl.schema_id", $"Where tbl.type='U' And {filter.Concat(" And ","(",")")}", $"Order By tbl.name, sch.name;" }; // Query items. using (DbResultSet resultSet = instanceConsole.Database.ExecuteQuery(String.Join("\n", sql))) { while (resultSet != null && resultSet.HasRows && resultSet.NextRecord()) { NamedValue.Map values = resultSet.GetRecordValues(); TableListData tableData = new TableListData() { SchemaName = values.GetString(colSchemaName), TableName = values.GetString(colTableName), ColumnCount = values.GetLong(colColumnCount), IndexCount = values.GetLong(colIndexCount), RowCount = values.GetLong(colRowCount), }; responseData.Tables.Add(tableData); } } if (model.Paging.IsPaged) model.Paging.ItemCount = (ushort)responseData.Tables.Count; } // Complete response. responseData.SetPaging(model); responseData.Success = true; return Json(responseData); } //------------------------------------------------------------------- // Populate Repository Database Indices ajax request. //------------------------------------------------------------------- private class AjaxResponse_RepositoryIndexPopulation : AjaxResponse_Data { // Construction. public AjaxResponse_RepositoryIndexPopulation(SbmModel_Control model) : base(model) { } // Stats. public class StatsData { public int? PrimaryIndicesCreated { get; set; } public int? IndicesCreated { get; set; } public int? IndicesDropped { get; set; } } public StatsData Stats { get; } = new StatsData(); } //------------------------------------------------------------------- [HttpPost] [Route("Instance/Repository/Ajax/PopulateIndices")] public IActionResult Ajax_PopulateRepositoryDatabaseIndices(Model_RepositoryDatabase model) { String messageTitle = Localiser["label.database"]; AjaxResponse_RepositoryIndexPopulation responseData = new AjaxResponse_RepositoryIndexPopulation(model); // Validate session and referrer. if (!ValidReferer) return Forbid(); if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData); RefreshModel(model); // Record disposable items as they are created so all can be disposed when needed. using (DisposableCollection disposables = new DisposableCollection()) { // Validate Repository. SessionData_Control.Profile.Filter.RepositoryContext = model.DatabaseFilter.Context; if (StringUtil.IsBlank(model.DatabaseFilter.Context)) { SaLogger.Warn($"{SysUtil.Fn} Repository Context not supplied."); return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"])); } SbmcRepository repository = ControlInstanceMgr.GetRepositoryByContext(model.DatabaseFilter.Context); if (repository == null) { SaLogger.Warn($"{SysUtil.Fn} Repository does not exist. Context: {model.DatabaseFilter.Context}."); return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"])); } // Repository Console. SbmCoreInstanceConsole_Control instanceConsole = new SbmCoreInstanceConsole_Control(SessionData_Control, repository); disposables.Add(instanceConsole); SbmDatabaseConsole dbConsole = new SbmDatabaseConsole(instanceConsole.Internals.SessionContext); // Populate indices. SaLogger.Info($"{SysUtil.Fn} Populating indices for Repository Context '{model.DatabaseFilter.Context}'.", true); SacsDatabaseConsole.IndexStats indexStats = new SacsDatabaseConsole.IndexStats(); dbConsole.InstallDbIndices(indexStats); if (dbConsole.HasErrorState()) return Json(responseData.SetMessage(messageTitle, $"Error encountered: {dbConsole.ErrorStateMessage.Trim('.')}.")); // Statistics. if (indexStats.PrimaryIndicesCreated > 0) responseData.Stats.PrimaryIndicesCreated = indexStats.PrimaryIndicesCreated; if (indexStats.IndicesCreated > 0) responseData.Stats.IndicesCreated = indexStats.IndicesCreated; if (indexStats.IndicesDropped > 0) responseData.Stats.IndicesDropped = indexStats.IndicesDropped; List statsOutput = new List(); if (indexStats.PrimaryIndicesCreated > 0) statsOutput.Add($"Primary Created: {indexStats.PrimaryIndicesCreated}."); if (indexStats.IndicesCreated > 0) statsOutput.Add($"Indices Created: {indexStats.IndicesCreated}."); if (indexStats.IndicesDropped > 0) statsOutput.Add($"Indices dropped: {indexStats.IndicesDropped}."); responseData.SetMessage(messageTitle, $"Indices populated.\n{statsOutput.Concat("", "\n")}"); } // Complete response. responseData.Success = true; return Json(responseData); } //------------------------------------------------------------------- } //======================================================================= }