Exemple #1
0
        /// <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)
                }
            }
        }
        private void FillEntriesTypes()
        {
            // Change available target type lists for each source column without changing the list itself
            // If some current type is not present in the new schema then deselect this entry
            // If an entry is selected then it must have some type selected (it is error if an entry does not have a selected type)

            List <DcTable> targetTypes = GetSchemaTypes();

            DcTable defaultType = null;

            foreach (DcTable table in targetTypes)
            {
                if (StringSimilarity.SameTableName(table.Name, "String"))
                {
                    defaultType = table;
                    break;
                }
            }

            foreach (ColumnMappingEntry entry in Entries)
            {
                entry.TargetTypes.Clear();
                targetTypes.ForEach(x => entry.TargetTypes.Add(x));

                // Now find a good new match for the current type
                // In fact, it should be done by some automatic matching procedure for inter-schema primitive matches

                // Target type has been selected. Try to find the same type
                if (entry.TargetType != null)
                {
                    DcTable targetType = null;
                    foreach (DcTable table in targetTypes)
                    {
                        if (StringSimilarity.SameTableName(table.Name, entry.TargetType.Name))
                        {
                            targetType = table;
                            break; // Found
                        }
                    }
                    if (targetType != null) // Found
                    {
                        entry.TargetType = targetType;
                        continue;
                    }
                }

                // Either not selected or not found. Try to select the source type
                if (entry.Source.Output != null)
                {
                    DcTable targetType = null;
                    foreach (DcTable table in targetTypes)
                    {
                        if (StringSimilarity.SameTableName(table.Name, entry.Source.Output.Name))
                        {
                            targetType = table;
                            break; // Found
                        }
                    }
                    if (targetType != null) // Found
                    {
                        entry.TargetType = targetType;
                        continue;
                    }
                }

                // Nothing helps
                entry.TargetType = defaultType;
            }
        }