static TableGenerator() { CreateDateFieldNames = TemplateConstants.CreateDateFieldNames .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .ToDictionary(a => a); DestNavPropNames = new Dictionary <string, string>(); TemplateConstants.DestinationNavigationPropertyNames .Split(',') .ToList() .ForEach(a => { var parts = a.Split(':'); DestNavPropNames.Add( parts[0].Trim(), parts[1].Trim()); }); EditableColumns = TemplateConstants.EditableColumns .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .ToList() .Select(a => a.Trim()) .ToDictionary(a => a, a => a); EndDateFieldNames = TemplateConstants.EndDateFieldNames .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .ToDictionary(a => a); ExcludePopulateDatesInterface = TemplateConstants.ExcludePopulateDatesInterface .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .ToDictionary(a => a); ExcludeFieldsFromModelTable = TemplateConstants.ExcludeFieldsFromModelTable .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .ToList() .Select(a => a.Trim()) .ToDictionary(a => a, a => a); ModelsSubclassEffDateExcludedColumns = TemplateConstants.ModelsSubclassEffDateExcludedColumns .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .ToList() .Select(a => a.Trim()) .ToDictionary(a => a, a => a); ModifiedDateFieldNames = TemplateConstants.ModifiedDateFieldNames .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .ToDictionary(a => a); NavPropDisplayNames = new Dictionary <string, string>(); TemplateConstants.NavigationPropertyDisplayNames .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .ToList() .ForEach(a => { var parts = a.Split(':'); NavPropDisplayNames.Add( parts[0].Trim(), parts.Length < 2 || string.IsNullOrWhiteSpace(parts[1]) ? NamingUtil.GetDisplayName(parts[0].Trim().Split('.')[1]) : parts[1].Trim()); }); NavPropsToSkip = TemplateConstants.NavigationPropertiesToSkip .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .Select(a => a.Trim()) .ToDictionary(a => a); NewKeywordColumns = TemplateConstants.NewKeywordColumns .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .Select(a => a.Trim()) .ToDictionary(a => a); OverrideColumns = TemplateConstants.OverrideColumns .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .Select(a => a.Trim()) .ToDictionary(a => a); SourceNavPropNames = new Dictionary <string, string>(); TemplateConstants.SourceNavigationPropertyNames .Split(',') .ToList() .ForEach(a => { var parts = a.Split(':'); SourceNavPropNames.Add( parts[0].Trim(), parts[1].Trim()); }); StartDateFieldNames = TemplateConstants.StartDateFieldNames .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .ToDictionary(a => a); IsActiveFieldNames = TemplateConstants.IsActiveFieldNames .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .ToDictionary(a => a); DeactivatedDateFieldNames = TemplateConstants.DeactivatedDateFieldNames .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .ToDictionary(a => a); TablesToOptOutOfSubClass = TemplateConstants.TablesToOptOutOfSubClass .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .ToList() .Select(a => a.Trim()) .ToDictionary(a => a); }
private static IEnumerable <NavigationProperty> GenerateNavigationProperties( DataTable columnsTable, DataTable foreignKeyColumnsTable, DataTable foreignKeysTable, DataTable tablesTable, Table table, IReadOnlyCollection <Table> tables) { var props = new List <NavigationProperty>(); // get foreign keys var foreignKeys = DbUtil.GetForeignKeysByTableId( columnsTable, foreignKeysTable, foreignKeyColumnsTable, tablesTable, table.ObjectId, table.TableName); // for each foreign key, foreignKeys.ForEach(a => { var isDestinationForeignKeyAllNonNullable = IsDestinationNullable(a, columnsTable); var isSourceForeignKeyAlsoPrimaryKey = IsSourcePrimaryKey(table, a); var type = EntityDesignUtil.Singularize( NamingUtil.GetTableName(a.DestinationTableName)); var srcCol = a.Columns[0].SourceColumn; var prop = new NavigationProperty { DestinationMultiplicity = // Zero: if any source foreign key columns are nullable !isDestinationForeignKeyAllNonNullable ? Multiplicity.Zero // One: not Zero : Multiplicity.One, ForeignKey = a, // *-1, 1-0/1 Name = SourceNavPropNames.TryGetValue( a.SourceTableName + "." + string.Join("|", a.Columns.Select(b => b.SourceColumn)), out var sourcePropName) ? sourcePropName : srcCol.ToLower().EndsWith("id") && srcCol.Length > 2 ? srcCol.Substring(0, srcCol.Length - 2) : type, SourceMultiplicity = isSourceForeignKeyAlsoPrimaryKey ? Multiplicity.One : Multiplicity.Many, Type = type }; // only add if not in NavigationPropertiesToSkip if (!NavPropsToSkip.ContainsKey(table.GeneratedName + "." + prop.Name)) { props.Add(prop); } // get destination table if (tables == null) { return; } { var destTable = tables .FirstOrDefault(b => b.TableName == a.DestinationTableName); type = EntityDesignUtil.Singularize( NamingUtil.GetTableName(a.SourceTableName)); var destProp = new NavigationProperty { DestinationMultiplicity = prop.SourceMultiplicity, ForeignKey = a, InverseProperty = prop.Name, Name = DestNavPropNames.TryGetValue( a.SourceTableName + "." + a.Columns[0].SourceColumn, out var destPropName) ? destPropName : prop.SourceMultiplicity == Multiplicity.Many ? EntityDesignUtil.Pluralize(type) : type, SourceMultiplicity = prop.DestinationMultiplicity, Type = prop.SourceMultiplicity == Multiplicity.Many ? "ICollection<" + type + ">" : type }; if (destTable != null && !NavPropsToSkip.ContainsKey(destTable.GeneratedName + "." + destProp.Name)) { destTable.NavigationProperties.Add(destProp); } } }); // var isManyToMany = AreAllColumnsForeignKeys // The relationship is many-to-many only if the // relationship table only contains primary keys // of both entities, and no other fields. // 0, 1, *: 0-1, 1-0, 1->1, 1<-1, 0-*, 1-*, *-0, *-1, *-* // if 0-1, // add single, non-nullable navigation property // of foreign key destination table class, // and ensure foreign key destination table class // has non-required navigation property to current table class // if 1-0, // do nothing, as non-required navigation property will be added // when processing other side of foreign key relationship // if 1->1, // add single, non-nullable navigation property // of foreign key destination table class, // and ensure foreign key destination table class // has required navigation property to current table class // if 1<-1, // required navigation property will be added // when processing other side of foreign key relationship // if 0-*, // add public virtual ICollection of // foreign key destination table class, // and ensure foreign key destination table class // has non-required navigation property to current table class // if 1-*, // add public virtual ICollection // of foreign key destination table class, // and ensure foreign key destination table class // has required navigation property to current table class // if *-0, // do nothing, as non-required navigation property will be added // when processing other side of foreign key relationship // if *-1, // do nothing, as required navigation property will be added // when processing other side of foreign key relationship // if *-*, // well, there are no such tables, according to the // Entity Framework definition, which is that all columns // in the join table being both in the join table primary key, // and a foreign key pointing from the join table to one of the // joined tables. return(props); }