private void BuildVirtualKeys(List <VirtualForeignKey> keys, MetadataTable mt, MetadataDatabase mdb, bool PrimaryKeyIndexOnly) { foreach (VirtualForeignKey vfk in keys) { MetadataForeignKey mfk = new MetadataForeignKey() { ID = 0, Name = vfk.values[0].Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)[0], ReferencedKey = "", ReferencedTable = vfk.values[0].Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)[1], ReferencedSchema = vfk.values[0].Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)[2], Parent = mt, IsVirtual = true }; MetadataTable mtref = null; if (!mdb.Tables.TryGetValue(mfk.ReferencedSchema + "." + mfk.ReferencedTable, out mtref)) { bool self = false; if (mfk.ReferencedSchema == mt.Schema && mfk.ReferencedTable == mt.Name) { self = true; } mtref = BuildMetadata(mdb, mfk.ReferencedTable, mfk.ReferencedSchema, PrimaryKeyIndexOnly, self); } for (int i = 1; i < vfk.values.Length; i++) { MetadataColumnReference mcf = new MetadataColumnReference() { ReferencedColumn = mtref[vfk.values[i].Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries)[1]], }; string from = vfk.values[i].Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries)[0]; if (from.StartsWith("\"")) { MetadataColumn mcVirtual = new MetadataColumn() { Name = from, IsForeignKey = true, ID = 0, SqlDataType = SqlDbType.NVarChar, Nullable = false, Length = 0, IsComputed = true, DataType = typeof(string), }; mcf.Column = mcVirtual; mcf.Name = from; } else { mcf.Column = mt[from]; mcf.Name = mcf.Column.Name; } mfk.ColumnReferences.Add(mcf); } mt.ForeignKeys.AddOrUpdate(mfk.Name, mfk, (k, v) => { return(mfk); }); } }
private MetadataTable BuildMetadata(MetadataDatabase mdb, Microsoft.SqlServer.Management.Smo.Table table, bool PrimaryKeyIndexOnly = true, bool SelfJoin = false) { MetadataTable mt = null; List <VirtualForeignKey> VirtualKeys = new List <VirtualForeignKey>(); table.Refresh(); if (mdb.Tables.TryGetValue(table.Name, out mt)) { return(mt); } mt = new MetadataTable() { ID = table.ID, Schema = table.Schema, Name = table.Name, //Parent = mdb }; mt.TitleColumn = GetExtendedProperty("TitleColumn", table.ExtendedProperties); string[] values = GetExtendedProperty("DisplayName", table.ExtendedProperties, new char[] { '\r', '\n' }); if (values != null) { foreach (string value in values) { string[] v = value.Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries); mt.DisplayNames.TryAdd(Convert.ToInt32(v[0]), v[1]); } } values = GetExtendedProperty("Lists", table.ExtendedProperties, new char[] { '\r', '\n' }); if (values != null) { foreach (string value in values) { string[] v = value.Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries); List <string> v2 = v[1].Split(',').ToList(); if (!mt.ListDefinitions.TryAdd(v[0].Trim(), v2)) { throw new InvalidOperationException(string.Format("The TinySql.Lists extended property is invalid for the table '{0}'", table.Name)); } } } foreach (Microsoft.SqlServer.Management.Smo.Column column in table.Columns) { try { MetadataColumn col = new MetadataColumn() { ID = column.ID, Parent = mt, //Database = mdb, Name = column.Name, Collation = column.Collation, Default = column.Default, IsComputed = column.Computed, ComputedText = column.ComputedText, IsPrimaryKey = column.InPrimaryKey, IsIdentity = column.Identity, IsForeignKey = column.IsForeignKey, IdentityIncrement = column.IdentityIncrement, IdentitySeed = column.IdentitySeed, Nullable = column.Nullable, IsRowGuid = column.RowGuidCol }; BuildColumnDataType(col, column); values = GetExtendedProperty("DisplayName", column.ExtendedProperties, new char[] { '\r', '\n' }); if (values != null) { foreach (string value in values) { if (!value.Contains("=")) { col.DisplayNames.TryAdd(SqlBuilder.DefaultCulture.LCID, value); } else { string[] v = value.Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries); col.DisplayNames.TryAdd(Convert.ToInt32(v[0]), v[1]); } } } col.IncludeColumns = GetExtendedProperty("IncludeColumns", column.ExtendedProperties, new char[] { ',' }); values = GetExtendedProperty("FK", column.ExtendedProperties, new char[] { '\r', '\n' }); if (values != null) { VirtualKeys.Add(new VirtualForeignKey() { Column = col, values = values }); col.IsForeignKey = true; } mt.Columns.AddOrUpdate(col.Name, col, (k, v) => { return(col); }); } catch (Exception exColumn) { throw new InvalidOperationException(string.Format("Unable to generate the column {0}", column.Name), exColumn); } } foreach (Index idx in table.Indexes) { if (!PrimaryKeyIndexOnly || idx.IndexKeyType == IndexKeyType.DriPrimaryKey) { Key key = new Key() { ID = idx.ID, Parent = mt, Database = mdb, Name = idx.Name, IsUnique = idx.IsUnique, IsPrimaryKey = idx.IndexKeyType == IndexKeyType.DriPrimaryKey }; foreach (IndexedColumn c in idx.IndexedColumns) { key.Columns.Add(mt[c.Name]); } mt.Indexes.AddOrUpdate(key.Name, key, (k, v) => { return(key); }); } } if (!SelfJoin) { foreach (ForeignKey FK in table.ForeignKeys) { MetadataForeignKey mfk = new MetadataForeignKey() { ID = FK.ID, Parent = mt, Database = mdb, Name = FK.Name, ReferencedKey = FK.ReferencedKey, ReferencedSchema = FK.ReferencedTableSchema, ReferencedTable = FK.ReferencedTable }; MetadataTable mtref = null; if (!mdb.Tables.TryGetValue(mfk.ReferencedSchema + "." + mfk.ReferencedTable, out mtref)) { bool self = false; if ((mfk.ReferencedSchema == mt.Schema && mfk.ReferencedTable == mt.Name) || TablesInProgress.Contains(mfk.ReferencedSchema + "." + mfk.ReferencedTable)) { self = true; } TablesInProgress.Add(mfk.ReferencedSchema + "." + mfk.ReferencedTable); mtref = BuildMetadata(mdb, mfk.ReferencedTable, mfk.ReferencedSchema, PrimaryKeyIndexOnly, self); } foreach (ForeignKeyColumn cc in FK.Columns) { mfk.ColumnReferences.Add(new MetadataColumnReference() { Name = cc.Name, Column = mt[cc.Name], ReferencedColumn = mtref[cc.ReferencedColumn] }); } mt.ForeignKeys.AddOrUpdate(mfk.Name, mfk, (key, existing) => { return(mfk); }); } } if (VirtualKeys.Count > 0) { BuildVirtualKeys(VirtualKeys, mt, mdb, PrimaryKeyIndexOnly); } mdb.Tables.AddOrUpdate(mt.Schema + "." + mt.Name, mt, (key, existing) => { return(mt); }); return(mt); }