/// <summary> /// Load meta data from dotwebdb. /// </summary> /// <param name="sharedContext">Indicates that dbContext used in the process is the shared one.</param> public void LoadFromConfig(bool sharedContext = false) { if (string.IsNullOrEmpty(ConfigurationManager.AppSettings["appId"])) { throw new ArgumentException("appId must be specified in config."); } appId = int.Parse(ConfigurationManager.AppSettings["appId"].ToString()); if (sharedContext && dbConfig == null) { throw new ArgumentException("using shared context requires initialization."); } var context = dbConfig; if (!sharedContext) { context = new DotWebDb(); } schemaInfo.App = context.Apps .Include(a => a.Groups) .Include(a => a.Groups.Select(g => g.Modules)) .SingleOrDefault(a => a.Id == appId); schemaInfo.Tables = context.Tables .Include(t => t.Columns) .Include(t => t.Children) .Include(t => t.App) .Where(t => t.AppId == appId).ToList(); if (!sharedContext) { context.Dispose(); } }
/// <summary> /// Ensure that appId key presents in the configuration file. Every web application must has corresponding appId. /// </summary> /// <param name="context">An instance of <see cref="DotWebDb"/>.</param> private void EnsureApp(DotWebDb context) { if (string.IsNullOrEmpty(ConfigurationManager.AppSettings["appId"])) { throw new ArgumentException("appId must be specified in config."); } appId = int.Parse(ConfigurationManager.AppSettings["appId"].ToString()); var app = context.Apps.SingleOrDefault(a => a.Id == appId); if (app == null) { app = new App(); // App is initiated with a default value var appName = "Sample App " + DateTime.Today.ToShortDateString(); if (!string.IsNullOrEmpty(ConfigurationManager.AppSettings["appName"])) { // If appName presents in configuration file, use it appName = ConfigurationManager.AppSettings["appName"]; } app.Id = appId; app.Name = appName; app.Description = "This app was automatically generated from DbInspector, please change the name and description appropriately."; context.Apps.Add(app); context.SaveChanges(); } schemaInfo.App = app; }
/// <summary> /// Look up display column can be determined manually in DotWeb admin interface. But, upon auto-generation /// it will be deducted from column which name is Name or Title. It thera are no such column names, the /// the first column will be used instead. /// </summary> /// <param name="context"></param> private void DetermineColumnForLookUpDisplay(DotWebDb context) { var tables = context.Tables.Include(t => t.Columns).Where(t => t.AppId == appId && t.LookUpDisplayColumnId == null); foreach (var table in tables) { // Determines lookup display column var lookUpColumns = table.Columns.Where(c => c.Name.Equals("Name", StringComparison.InvariantCultureIgnoreCase) || c.Name.Equals("Title", StringComparison.InvariantCultureIgnoreCase)).ToList(); if (lookUpColumns.Count > 0) { table.LookUpDisplayColumnId = lookUpColumns[0].Id; } else { lookUpColumns = table.Columns.Where(c => c.DataType == TypeCode.String).ToList(); if (lookUpColumns.Count > 0) { table.LookUpDisplayColumnId = lookUpColumns[0].Id; } else { table.LookUpDisplayColumnId = table.Columns[0].Id; } } } }
/// <summary> /// This is to generate menu items and groups for navigation menu purpose. /// </summary> /// <param name="context">An instance of <see cref="DotWebDb"/>.</param> private void GenerateNavigationModules(DotWebDb context) { foreach (var tableMeta in schemaInfo.Tables) { string groupName = tableMeta.SchemaName == "dbo" ? schemaInfo.App.DefaultGroupName : tableMeta.SchemaName; var group = schemaInfo.App.Groups.FirstOrDefault( g => g.AppId == appId && g.Name.Equals(groupName, StringComparison.InvariantCultureIgnoreCase)); if (group == null) { group = new ModuleGroup() { AppId = appId, Name = groupName, Title = groupName, OrderNo = schemaInfo.App.Groups.Count == 0 ? 1 : schemaInfo.App.Groups.Count + 1, }; schemaInfo.App.Groups.Add(group); } var dbModule = context.Modules.Include(m => m.Group).SingleOrDefault(m => m.TableName.Equals(tableMeta.Name, StringComparison.InvariantCultureIgnoreCase) && m.Group.AppId == appId); if (dbModule == null) { group.Modules.Add(new Module() { TableName = tableMeta.Name, Title = tableMeta.Name.ToTitleCase(), OrderNo = group.Modules.Count == 0 ? 1 : group.Modules.Count + 1, ModuleType = ModuleType.AutoGenerated }); } } }
/// <summary> /// Main entry for generation purpose. /// </summary> /// <param name="connectionStringName">Connection string name stored in configuration file.</param> public void GenerateFromDb(string connectionStringName) { dbConfig = new DotWebDb(); EnsureApp(dbConfig); Inspect(connectionStringName); GenerateNavigationModules(dbConfig); SaveToConfig(true); DetermineColumnForLookUpDisplay(dbConfig); SaveToConfig(true); dbConfig.Dispose(); }
public void Generate(string assemblyName) { try { dbApp = GetDbContextFromAssembly(assemblyName); if (dbApp == null) { throw new ArgumentException("ERROR: There is no dbContext descendant class in the assembly."); } dbConfig = new DotWebDb(); if (string.IsNullOrEmpty(ConfigurationManager.AppSettings["appId"])) { throw new ArgumentException("ERROR: appId must be specified in config."); } appId = int.Parse(ConfigurationManager.AppSettings["appId"]); app = dbConfig.Apps.Find(appId); if (app == null) { throw new ArgumentException(string.Format("ERROR: appId {0} not found in configdb.", appId)); } EnsureOutputDirectory(); EnsureTemplateDirectory(); EmptyOutputDirectory(); DeleteExistingNavigation(); var properties = dbApp.GetDbSetProperties(); var entitySets = properties.ToDictionary(x => x.Name, x => x.GetValue(dbApp, null)); if (entitySets.Count() == 0) { Console.WriteLine("WARNING: No entities in dbContext!"); } else { foreach (var entitySetName in entitySets.Keys) { var entityType = GetEntityTypeFromEntitySet(entitySets[entitySetName]); InspectEntity(entitySetName, entityType); } foreach (var entitySetName in entitySets.Keys) { var entityType = GetEntityTypeFromEntitySet(entitySets[entitySetName]); if (!entitiesMeta[entityType.Name].IsScaffold) { continue; } ReinspectEntity(entityType); } foreach (var entitySetName in entitySets.Keys) { var entityType = GetEntityTypeFromEntitySet(entitySets[entitySetName]); if (!entitiesMeta[entityType.Name].IsScaffold) { continue; } ProcessEntity(entitySetName, entitiesMeta[entityType.Name]); } } } finally { if (dbConfig != null) { dbConfig.Dispose(); } if (dbApp != null) { dbApp.Dispose(); } } }
/// <summary> /// Save the inspection result to database. /// </summary> /// <param name="sharedContext">Indicates that dbContext used in the process is the shared one.</param> public void SaveToConfig(bool sharedContext = false) { if (string.IsNullOrEmpty(ConfigurationManager.AppSettings["appId"])) { throw new ArgumentException("appId must be specified in config."); } appId = int.Parse(ConfigurationManager.AppSettings["appId"].ToString()); if (sharedContext && dbConfig == null) { throw new ArgumentException("Using shared context requires initialization."); } var context = dbConfig; if (!sharedContext) { context = new DotWebDb(); } EnsureApp(context); // Save tables foreach (var tableMeta in SchemaInfo.Tables) { Console.WriteLine("Processing table " + tableMeta.Name); TableMeta dbTable = context.Tables .Include(t => t.Columns) .Include(t => t.Columns.Select(c => c.ReferenceTable)) .Include(t => t.Children) .Include(t => t.Children.Select(c => c.Parent)) .Include(t => t.Children.Select(c => c.Child)) .Include(t => t.App) .SingleOrDefault(t => t.Name == tableMeta.Name && t.AppId == appId); var newTable = false; if (dbTable == null) { // Add table dbTable = tableMeta; newTable = true; } else { // Update existing table dbTable.SchemaName = tableMeta.SchemaName; } foreach (var columnMeta in tableMeta.Columns) { Console.WriteLine(" Processing column " + columnMeta.Name + " of table " + tableMeta.Name); ColumnMeta dbColumn = context.Columns.SingleOrDefault(c => c.TableId == dbTable.Id && c.Name == columnMeta.Name); var newColumn = false; if (dbColumn == null) { // Add columns dbColumn = columnMeta; dbColumn.Table = dbTable; newColumn = true; } else { // Update existing column dbColumn.DataType = columnMeta.DataType; dbColumn.IsForeignKey = columnMeta.IsForeignKey; dbColumn.IsIdentity = columnMeta.IsIdentity; dbColumn.IsPrimaryKey = columnMeta.IsPrimaryKey; dbColumn.IsRequired = columnMeta.IsRequired; dbColumn.MaxLength = columnMeta.MaxLength; } if (columnMeta.ReferenceTable != null && (newColumn || dbColumn.ReferenceTable.Name != columnMeta.ReferenceTable.Name)) { var dbRefTable = context.Tables.SingleOrDefault(t => tableMeta.AppId == appId && t.Name.Equals(columnMeta.ReferenceTable.Name, StringComparison.InvariantCultureIgnoreCase)); if (dbRefTable != null) { dbColumn.ReferenceTable = dbRefTable; } } if (newColumn && !newTable) { dbTable.Columns.Add(dbColumn); } } // removes columns var removedColumns = new List <ColumnMeta>(); foreach (var dbColumn in dbTable.Columns) { ColumnMeta column = tableMeta.Columns.SingleOrDefault(c => c.Name.Equals(dbColumn.Name, StringComparison.InvariantCultureIgnoreCase)); if (column == null) { Console.WriteLine(" Removing column " + dbColumn.Name + " from table " + tableMeta.Name); // column has been deleted or renamed, so delete related metadata removedColumns.Add(dbColumn); } } if (removedColumns.Count > 0) { context.Columns.RemoveRange(removedColumns); } // Processing table meta relations foreach (var tableMetaRelation in tableMeta.Children) { Console.WriteLine(" Processing relation " + tableMetaRelation.Name + " of table " + tableMeta.Name); TableMetaRelation dbRelation = context.TableRelations.Include(r => r.Child).Include(r => r.Parent) .SingleOrDefault(r => r.Name.Equals(tableMetaRelation.Name, StringComparison.InvariantCultureIgnoreCase)); if (dbRelation == null) { // Add relation var dbChild = context.Tables.SingleOrDefault(t => t.AppId == appId && t.Name == tableMetaRelation.Child.Name); if (dbChild != null) { tableMetaRelation.Child = dbChild; } var dbParent = context.Tables.SingleOrDefault(t => t.AppId == appId && t.Name == tableMetaRelation.Parent.Name); if (dbParent != null) { tableMetaRelation.Parent = dbParent; } dbRelation = tableMetaRelation; context.TableRelations.Add(dbRelation); } else { // Update existing relation if (dbRelation.Child.Name != tableMetaRelation.Child.Name) { var dbChild = context.Tables.SingleOrDefault(t => t.AppId == appId && t.Name == tableMetaRelation.Child.Name); if (dbChild != null) { dbRelation.Child = dbChild; } } if (dbRelation.Parent.Name != tableMetaRelation.Parent.Name) { var dbParent = context.Tables.SingleOrDefault(t => t.AppId == appId && t.Name == tableMetaRelation.Parent.Name); if (dbParent != null) { dbRelation.Parent = dbParent; } } } } if (newTable) { context.Tables.Add(dbTable); } if (context.ChangeTracker.HasChanges()) { context.SaveChanges(); } } // Save navigation var newGroups = new List <ModuleGroup>(); foreach (var group in schemaInfo.App.Groups) { var newModules = new List <Module>(); var dbGroup = context.ModuleGroups.SingleOrDefault(g => g.Name == group.Name && g.AppId == appId); foreach (var module in group.Modules) { var dbModule = context.Modules.Include(m => m.Group).SingleOrDefault(m => m.ModuleType == ModuleType.AutoGenerated && m.TableName == module.TableName && m.Group.AppId == appId); if (dbModule == null) { if (dbGroup != null) { module.Group = dbGroup; } newModules.Add(module); } } if (newModules.Count > 0) { context.Modules.AddRange(newModules); } } if (!sharedContext) { context.Dispose(); } }