public FKField(int fieldId, string column, int typeId, string typeName, int panelId, IFK fk, PropertyCollection attr = null, PropertyCollection rules = null) : base(fieldId, column, typeId, typeName, panelId, attr, rules) { this.fk = fk; }
/// <summary> /// checks if edited fields exist in webDB and their types are adequate, checks constraints on FKs and mapping tables, /// also checks if controls` dataTables` columns exist and everything that has to be inserted in DB is a required field, /// whether attributes don`t colide and every panel has something to display. /// As it goes through the Panel, it fires an ArchitectureError event. /// </summary> /// <param name="proposalPanel"></param> /// <param name="recursive">run itself on panel children</param> /// <returns>true if no errors found, true othervise</returns> public bool checkPanelProposal(IPanel proposalPanel, bool recursive = true) // non-recursive checking after the initial check - after panel modification { string messageBeginning = "In panel " + (proposalPanel.viewAttr.ContainsKey(CC.PANEL_NAME) ? (proposalPanel.viewAttr[CC.PANEL_NAME] + " (" + proposalPanel.tableName + ") ") : ("of type " + proposalPanel.typeName + " for " + proposalPanel.tableName)) + ": "; DataColumnCollection cols = stats.columnTypes(proposalPanel.tableName); if (cols.Count == 0) { Error(this, new ArchitectureErrorEventArgs(messageBeginning + "table not found or has 0 columns", proposalPanel.tableName)); return(false); } List <IFK> FKs = stats.foreignKeys(proposalPanel.tableName); bool good = true; if (proposalPanel.typeName == PanelTypes.Editable.ToString() || proposalPanel.typeName == PanelTypes.NavTable.ToString()) // this is indeed the only panelType containing fields { bool isNavTable = proposalPanel.typeName == PanelTypes.NavTable.ToString(); foreach (IField field in proposalPanel.fields) { if (field.typeName == FieldTypes.Holder.ToString()) { continue; } if (!cols.Contains(field.column)) { Error(this, new ArchitectureErrorEventArgs(messageBeginning + "the column " + field.column + "managed by the field does not exist in table", proposalPanel, field)); good = false; } else { if (!(field is IFKField) && !(field is IM2NMapping) && !isNavTable) // NavTable won`t be edited in the panel { PropertyCollection r = field.rules; if (cols[field.column].AllowDBNull == false && !r.ContainsKey(CC.RULES_REQUIRED)) { Error(this, new ArchitectureErrorEventArgs(messageBeginning + "the column " + field.column + " cannot be set to null, but the coresponding field is not required", proposalPanel, field)); good = false; } if ((r.ContainsKey(CC.RULUES_DECIMAL) || r.ContainsKey(CC.RULES_ORDINAL)) && !(typeof(long).IsAssignableFrom(cols[field.column].DataType))) { Error(this, new ArchitectureErrorEventArgs(messageBeginning + "the column " + field.column + " is of type " + cols[field.column].DataType.ToString() + ", thus cannot be edited as a decimalnumber", proposalPanel, field)); good = false; } if ((r.ContainsKey(CC.RULES_DATE) || r.ContainsKey(CC.RULES_DATETIME)) && !(cols[field.column].DataType == typeof(DateTime))) { Error(this, new ArchitectureErrorEventArgs(messageBeginning + "the column " + field.column + " is not a date / datetime, thus cannot be edited as a date", proposalPanel, field)); good = false; } } else if (field is IM2NMappingField) { // just cannot occur in a NavTable, but just in case... if (isNavTable) { throw new Exception("Cannot display a M2NMapping in NavTable"); } IM2NMapping thisMapping = ((IM2NMappingField)field).mapping; if (!mappings.Contains(thisMapping)) { Error(this, new ArchitectureErrorEventArgs(messageBeginning + "the schema " + "does not define an usual M2NMapping batween tables " + thisMapping.myTable + " and " + thisMapping.refTable + " using " + thisMapping.mapTable + " as a map table", proposalPanel, field)); good = false; } } else if (field is IFKField) { IFK fieldFK = ((IFKField)field).fk; if (!FKs.Contains(fieldFK)) { Error(this, new ArchitectureErrorEventArgs(messageBeginning + "the column " + field.column + " is not a foreign key representable by the FK field", proposalPanel, field)); good = false; } } } } } // controls... PanelTypes PTEnum = (PanelTypes)Enum.Parse(typeof(PanelTypes), proposalPanel.typeName); if (PTEnum == PanelTypes.NavTable || PTEnum == PanelTypes.NavTree || PTEnum == PanelTypes.MenuDrop) { if (proposalPanel.controlAttr.ContainsKey(CC.NAV_THROUGH_PANELS)) { if (proposalPanel.tableName != null) { Error(this, new ArchitectureErrorEventArgs(messageBeginning + "Panel that navigates through panels " + "cannot have tableName set", proposalPanel.tableName)); good = false; } } else if (proposalPanel.controlAttr.ContainsKey(CC.NAV_THROUGH_RECORDS)) { if (!proposalPanel.controlAttr.ContainsKey(CC.NAV_PANEL_ID)) { Error(this, new ArchitectureErrorEventArgs(messageBeginning + "Navigation panel " + "that does not navigate through panels must have target panel id set", proposalPanel, proposalPanel.controls[0])); good = false; } } } // TODO & TODO & TODO (CONTROLS & OTHER PROPERTIES) // OR allow the admin-user take valid steps only (?) if (recursive) { foreach (IPanel child in proposalPanel.children) { good = good && checkPanelProposal(child, true); } } return(good); }
/// <summary> /// Ignores mappings, displays first 4 columns in a classic NavTable /// or the first display column in a NavTree if a self-referential FK is present. /// navtable includes edit and delete action buttons, second control - insert button /// </summary> /// <param name="tableName">string</param> /// <returns>IPanel</returns> private IPanel proposeSummaryPanel(string tableName) { DataColumnCollection cols = stats.columnTypes(tableName); List <IFK> FKs = stats.foreignKeys(tableName); // a table with more than one self-referential FK is improbable List <IFK> selfRefs = new List <IFK>(from FK in FKs where FK.myTable == FK.refTable select FK as IFK); List <string> PKCols = stats.primaryKeyCols(tableName); IFK selfRefFK = null; // strict hierarchy structure validation - not nice => no Tree string hierarchyExplanation = "(For a tree-like navigation within view, the table must have exactly one FK pointing " + " to it`s PK column. (It can of course have other FKs refering to other tables.))"; if (selfRefs.Count > 1) { Warning(this, new ArchitectWarningEventArgs( "Unexpected hierarchy table structure for " + tableName + " - multiple self-referential columns. " + hierarchyExplanation, tableName)); } else if (selfRefs.Count == 1 && PKCols.Count == 1) { selfRefFK = selfRefs.First(); if (PKCols.Count > 1) { Warning(this, new ArchitectWarningEventArgs( "Hierarchical table " + tableName + " does have a signle-column PK. " + hierarchyExplanation, tableName)); selfRefFK = null; // remove the selfRefFK => as if there was no hierarchy } if (selfRefFK.refColumn != PKCols[0]) { selfRefFK = null; Warning(this, new ArchitectWarningEventArgs("The self-referential FK in table " + tableName + " must refer to the PK column. " + hierarchyExplanation, tableName)); } } List <string> displayColOrder = DisplayColOrder(tableName); PropertyCollection controlProps = new PropertyCollection(); PropertyCollection displayProps = new PropertyCollection(); displayProps.Add(CC.PANEL_DISPLAY_COLUMN_ORDER, String.Join(",", displayColOrder)); displayProps.Add(CC.PANEL_NAME, tableName); controlProps.Add(UserAction.View.ToString() + CC.CONTROL_ACCESS_LEVEL_REQUIRED_SUFFIX, 1); IControl control; DataTable controlTab = new DataTable(); PanelTypes panelType; List <IField> fields = new List <IField>(); if (selfRefFK == null) { //displayProps.Add(CC.NAVTAB_COLUMNS_DISLAYED, CC.NAVTAB_COLUMNS_DISLAYED_DEFAULT); // table takes first four display-suitable fields; the above is not neccessary, in Navtable Columns are fields foreach (string column in displayColOrder.Take(CC.NAVTAB_COLUMNS_DISLAYED_DEFAULT)) { //controlTab.Columns.Add(column); if (FKs.Any(x => x.myColumn == column)) { IFK myFK = FKs.Find(x => x.myColumn == column); fields.Add(new FKField(0, column, fieldTypeIdMap[FieldTypes.Varchar], FieldTypes.Varchar.ToString(), 0, myFK)); } else { fields.Add(new Field(0, column, fieldTypeIdMap[FieldTypes.Varchar], FieldTypes.Varchar.ToString(), 0)); } fields.OrderBy(x => displayColOrder.IndexOf(x.column)); // to maintain the order from displayColOrder without further properties } control = new Control(controlTab, PKCols, UserAction.Update); panelType = PanelTypes.NavTable; } else { controlProps.Add(CC.CONTROL_HIERARCHY_SELF_FK_COL, selfRefFK.myColumn); controlTab.Columns.Add(PKCols[0]); controlTab.Columns.Add(selfRefFK.myColumn); controlTab.Columns.Add(displayColOrder[0]); control = new TreeControl(controlTab, PKCols[0], selfRefFK.myColumn, displayColOrder[0], UserAction.Update); panelType = PanelTypes.NavTree; } List <IControl> controls = new List <IControl>(); controls.Add(control); return(new Panel(tableName, 0, panelTypeIdMp[panelType], panelType.ToString(), new List <IPanel>(), fields, controls, PKCols, null, displayProps, controlProps)); }
private void RewriteFieldProperties(IField field) { //set control properties Dictionary <string, object> insertVals = new Dictionary <string, object>(); insertVals["id_field"] = field.fieldId; insertVals["concerns"] = CC.ATTR_CONTROLS; IFK fk = null; IM2NMapping mapping = null; if (field is FKField) { fk = (field as FKField).fk; } if (field is M2NMappingField) { fk = mapping = (field as M2NMappingField).mapping; } if (fk != null) { insertVals["name"] = CC.FIELD_REF_TABLE; insertVals["val"] = fk.refTable; query("REPLACE INTO fields_meta", insertVals); insertVals["name"] = CC.FIELD_REF_COLUMN; insertVals["val"] = fk.refColumn; query("REPLACE INTO fields_meta", insertVals); insertVals["name"] = CC.FIELD_DISPLAY_COLUMN; insertVals["val"] = fk.displayColumn; query("REPLACE INTO fields_meta", insertVals); } if (mapping != null) { insertVals["name"] = CC.FIELD_REF_TABLE; insertVals["val"] = mapping.mapTable; query("REPLACE INTO fields_meta", insertVals); insertVals["name"] = CC.FIELD_MAP_MY_COLUMN; insertVals["val"] = mapping.myColumn; query("REPLACE INTO fields_meta", insertVals); insertVals["name"] = CC.FIELD_MAP_REF_COLUMN; insertVals["val"] = mapping.refColumn; query("REPLACE INTO fields_meta", insertVals); } // validation rules & view properties - just copy insertVals = new Dictionary <string, object>(); insertVals["id_field"] = field.fieldId; insertVals["concerns"] = "view"; foreach (string attrKey in field.attr.Keys) { insertVals["name"] = attrKey; insertVals["val"] = field.attr[attrKey].ToString(); query("REPLACE INTO fields_meta", insertVals); } insertVals["concerns"] = "validation"; foreach (string ruleKey in field.rules.Keys) { insertVals["name"] = ruleKey; insertVals["val"] = field.rules[ruleKey].ToString(); query("REPLACE INTO fields_meta", insertVals); } }