public override void FromJson(JObject json, DcSpace ws) { base.FromJson(json, ws); // Table RelationalTableName = (string)json["RelationalTableName"]; RelationalPkName = (string)json["RelationalPkName"]; // List of greater paths (relational attributes) if (json["greater_paths"] != null) { if (GreaterPaths == null) { GreaterPaths = new List <ColumnAtt>(); } foreach (JObject greater_path in json["greater_paths"]) { ColumnAtt path = (ColumnAtt)Utils.CreateObjectFromJson(greater_path); if (path != null) { path.FromJson(greater_path, ws); GreaterPaths.Add(path); } } } }
public void AddAllNonStoredPaths() { // The method adds entity (non-PK) columns from referenced (by FK) tables (recursively). int pathCounter = 0; ColumnAtt path = new ColumnAtt(""); PathEnumerator primPaths = new PathEnumerator(this, ColumnType.IDENTITY_ENTITY); foreach (ColumnAtt p in primPaths) { if (p.Size < 2) { continue; // All primitive paths are stored in this set. We need at least 2 segments. } // Check if this path already exists path.Segments = p.Segments; if (GetGreaterPath(path) != null) { continue; // Already exists } string pathName = "__inherited__" + ++pathCounter; ColumnAtt newPath = new ColumnAtt(pathName); newPath.Segments = new List <DcColumn>(p.Segments); newPath.RelationalColumnName = newPath.Name; // It actually will be used for relational queries newPath.RelationalFkName = path.RelationalFkName; // Belongs to the same FK newPath.RelationalPkName = null; //newPath.Input = this; //newPath.Output = p.Path[p.Length - 1].Output; AddGreaterPath(newPath); } }
public ColumnAtt GetGreaterPath(ColumnAtt path) { if (path == null || path.Segments == null) { return(null); } return(GetGreaterPath(path.Segments)); }
public List <ColumnAtt> GetGreaterPathsStartingWith(ColumnAtt path) { if (path == null || path.Segments == null) { return(new List <ColumnAtt>()); } return(GetGreaterPathsStartingWith(path.Segments)); }
public void RemoveGreaterPath(string name) { ColumnAtt path = GetGreaterPath(name); if (path != null) { RemoveGreaterPath(path); } }
/// <summary> /// Expand one attribute by building its path segments as dimension objects. /// Use the provided list of attributes for expansion recursively. This list essentially represents a schema. /// Also, adjust path names in special cases like empty name or simple structure. /// </summary> public void ExpandAttribute(List <ColumnAtt> attributes, List <DcColumn> columns) // Add and resolve attributes by creating dimension structure from FKs { ColumnAtt att = this; if (att.Segments.Count > 0) { return; // Already expanded (because of recursion) } bool isKey = !string.IsNullOrEmpty(att.RelationalPkName) || att.IsKey; if (string.IsNullOrEmpty(att.RelationalFkName)) // No FK - primitive column - end of recursion { // Find or create a primitive dim segment DcColumn seg = columns.FirstOrDefault(c => c.Input == att.Input && StringSimilarity.SameColumnName(((ColumnRel)c).RelationalFkName, att.RelationalFkName)); if (seg == null) { seg = new ColumnRel(att.RelationalColumnName, att.Input, att.Output, isKey, false); // Maybe copy constructor? ((ColumnRel)seg).RelationalFkName = att.RelationalFkName; columns.Add(seg); } att.InsertLast(seg); // add it to this attribute as a single segment } else { // There is FK - non-primitive column // Find target set and target attribute (name resolution) ColumnAtt tailAtt = attributes.FirstOrDefault(a => StringSimilarity.SameTableName(a.Input.Name, att.RelationalTargetTableName) && StringSimilarity.SameColumnName(a.Name, att.RelationalTargetColumnName)); DcTable gTab = tailAtt.Input; // Find or create a dim segment DcColumn seg = columns.FirstOrDefault(c => c.Input == att.Input && StringSimilarity.SameColumnName(((ColumnRel)c).RelationalFkName, att.RelationalFkName)); if (seg == null) { seg = new ColumnRel(att.RelationalFkName, att.Input, gTab, isKey, false); ((ColumnRel)seg).RelationalFkName = att.RelationalFkName; columns.Add(seg); } att.InsertLast(seg); // add it to this attribute as first segment // // Recursion. Expand tail attribute and add all segments from the tail attribute (continuation) // tailAtt.ExpandAttribute(attributes, columns); att.InsertLast(tailAtt); // Adjust name. How many attributes belong to the same FK as this attribute (FK composition) List <ColumnAtt> fkAtts = attributes.Where(a => a.Input == att.Input && StringSimilarity.SameColumnName(att.RelationalFkName, a.RelationalFkName)).ToList(); if (fkAtts.Count == 1) { seg.Name = att.RelationalColumnName; // Adjust name. For 1-column FK, name of the FK-dim is the column name (not the FK name) } } }
public void RemoveGreaterPath(ColumnAtt path) { Debug.Assert(path.Output != null && path.Input != null, "Wrong use: path must specify a lesser and greater sets before it can be removed from a set."); if (path.Output is TableRel) { ((TableRel)path.Output).LesserPaths.Remove(path); } if (path.Input is TableRel) { ((TableRel)path.Input).GreaterPaths.Remove(path); } }
// // What is Set::AddAllNonStoredPaths() ??? // /* * public void ImportSchema(List<string> tableNames = null) * { * if (tableNames == null) * { * tableNames = connection.ReadTables(); * } * * // Create all sets * foreach (string tableName in tableNames) * { * Set set = new Set(tableName); // Create a set * set.RelationalTableName = tableName; * this.AddTable(set, null); * } * * // Load columns and FKs as (complex) paths and (simple) FK-dimensions * foreach (string tableName in tableNames) * { * ImportPaths(tableName); * } * * List<ComTable> sets = Root.GetAllSubsets(); * foreach (ComTable set in sets) * { * foreach (DimPath path in set.GreaterPaths) * { * path.ExpandPath(); * } * } * * foreach (Set set in sets) * { * set.AddAllNonStoredPaths(); * } * } */ protected List <ColumnAtt> LoadAttributes(TableRel table) { // The created paths will be not be added to the schema (should be added manually) // The created paths are empty and do not store any dimensions (should be done/expanded separately by using the meta-data about PKs, FKs etc.) Debug.Assert(!table.IsPrimitive, "Wrong use: cannot load structure for primitive set."); List <ColumnAtt> attributes = new List <ColumnAtt>(); string tableName = table.RelationalTableName; DataTable pks = connection.GetPks(tableName); DataTable fks = connection.GetFks(tableName); DataTable columns = connection.GetColumns(tableName); foreach (DataRow col in columns.Rows) // Process all columns of the table (correspond to primitive paths of the set) { string columnName = col["COLUMN_NAME"].ToString(); string columnType = ((OleDbType)col["DATA_TYPE"]).ToString(); DcTable typeTable = Schema.GetPrimitiveType(columnType); // // Create an attribute object representing this column // ColumnAtt path = table.GetGreaterPathByColumnName(columnName); // It might have been already created (when processing other tables) if (path != null) { continue; } path = new ColumnAtt(columnName, table, typeTable); // // Set relational attribute of the object // path.RelationalColumnName = columnName; // Find PKs this attribute belongs to (among all PKs of this table) foreach (DataRow pk in pks.Rows) { if (!StringSimilarity.SameColumnName(columnName, (string)pk["COLUMN_NAME"])) { continue; } // Found PK this column belongs to path.RelationalPkName = (string)pk["PK_NAME"]; table.RelationalPkName = path.RelationalPkName; // OPTIMIZE: try to do it only once rather than for each attribute and try to identify and exclude multiple PKs (error) //path.IsIdentity = true; // We simply have to override this property as "RelationalPkName != null" or "RelationalPkName == table.RelationalPkName" break; // Assume that a column can belong to only one PK } // Find FKs this attribute belongs to (among all FKs of this table) foreach (DataRow fk in fks.Rows) { if (!StringSimilarity.SameColumnName(columnName, (string)fk["FK_COLUMN_NAME"])) { continue; } // Target PK name fk["PK_NAME"] is not stored and is not used because we assume that there is only one PK path.RelationalFkName = (string)fk["FK_NAME"]; path.RelationalTargetTableName = (string)fk["PK_TABLE_NAME"]; // Name of the target set of the simple dimension (first segment of this complex path) path.RelationalTargetColumnName = (string)fk["PK_COLUMN_NAME"]; // Next path/attribute name belonging to the target set break; // We assume that a column can belong to only one FK and do not continue with the rest of the FK-loop } attributes.Add(path); } return(attributes); }