public void Save() { lock (_sync) { CurrentSchema.ToJsonFile(CurrentSchema.File); } }
public SchemaResult SetForeignKey(string targetTable, string referencingTable, string referencingColumn, string referencedKey = null, INameFormatter nameFormatter = null) { try { Table table = CurrentSchema.GetTable(referencingTable); Table target = CurrentSchema.GetTable(targetTable); Column col = table[referencingColumn]; if (col.DataType == DataTypes.Int || col.DataType == DataTypes.Long) { ForeignKeyColumn fk = new ForeignKeyColumn(col, targetTable) { ReferencedKey = referencedKey ?? (target.Key != null ? target.Key.Name : "Id"), ReferencedTable = target.Name }; if (nameFormatter != null) { fk.ReferencedClass = nameFormatter.FormatClassName(targetTable); fk.ReferencingClass = nameFormatter.FormatClassName(referencingTable); fk.TableClassName = nameFormatter.FormatClassName(fk.TableName); fk.PropertyName = nameFormatter.FormatPropertyName(fk.TableName, fk.Name); } return(SetForeignKey(table, target, fk)); } else { throw new InvalidOperationException("The specified column must be a number type"); } } catch (Exception ex) { return(GetErrorResult(ex)); } }
/// <summary> /// Locates an element given an element locator. /// </summary> /// <param name="ElementLocator"> /// The locator specifying the element to find. /// </param> /// <returns> /// The element referenced by the locator; null if the element cannot be found. /// </returns> /// <remarks> /// This method should most likely be moved into a class which wraps <see cref="Element"/> /// collections with a value-added wrapper class. /// </remarks> private Element LocateElement(Locator ElementLocator) { foreach (XbrlSchema CurrentSchema in this.ValidatedFragment.Schemas) { var FoundElement = CurrentSchema.LocateElement(ElementLocator); if (FoundElement != null) { return(FoundElement); } } return(null); }
/// <summary> /// Gets the data type for the supplied attribute. /// </summary> /// <param name="attribute"> /// The attribute whose data type is returned. /// </param> /// <returns> /// The data type of the supplied attribute. A null reference will be returned /// if no matching element can be found for the supplied attribute. /// </returns> internal AnyType GetAttributeType(IAttribute attribute) { foreach (var CurrentSchema in SchemaList) { var matchingAttributeType = CurrentSchema.GetAttributeType(attribute); if (matchingAttributeType != null) { return(matchingAttributeType); } } return(null); }
/// <summary> /// Locates and element using an element locator. /// </summary> /// <param name="ElementLocator"> /// A locator for the element to be found. /// </param> /// <returns> /// A reference to the matching element. A null reference will be returned /// if no matching element can be found. /// </returns> internal Element LocateElement(Locator ElementLocator) { foreach (var CurrentSchema in SchemaList) { var matchingElement = CurrentSchema.LocateElement(ElementLocator); if (matchingElement != null) { return(matchingElement); } } return(null); }
/// <summary> /// Finds the <see cref="RoleType"/> object having the given ID. /// </summary> /// <param name="RoleTypeId"> /// The ID of the role type to find. /// </param> /// <returns> /// The <see cref="RoleType"/> object having the given ID, or null if no /// object can be found. /// </returns> internal RoleType GetRoleType(string RoleTypeId) { foreach (var CurrentSchema in SchemaList) { var matchingRoleType = CurrentSchema.GetRoleType(RoleTypeId); if (matchingRoleType != null) { return(matchingRoleType); } } return(null); }
/// <summary> /// Gets the schema containing the element with the given local name. /// </summary> /// <param name="elementLocalName"> /// The local name of the element to be found. /// </param> /// <returns> /// A reference to the schema containing the element. A null reference will be returned /// if no matching element can be found. /// </returns> public XbrlSchema GetSchemaContainingElement(string elementLocalName) { foreach (var CurrentSchema in SchemaList) { var FoundElement = CurrentSchema.GetElement(elementLocalName); if (FoundElement != null) { return(CurrentSchema); } } return(null); }
protected virtual SchemaResult SetForeignKey(Table table, Table target, ForeignKeyColumn fk) { CurrentSchema.AddForeignKey(fk); table.RemoveColumn(fk.Name); table.AddColumn(fk); target.ReferencingForeignKeys = GetReferencingForeignKeysForTable(target.Name); table.ForeignKeys = GetForeignKeysForTable(table.Name); if (AutoSave) { CurrentSchema.Save(); } return(new SchemaResult("ForeignKeyColumn set")); }
public SchemaResult SetKeyColumn(string tableName, string columnName) { try { Table table = CurrentSchema.GetTable(tableName); table.SetKeyColumn(columnName); if (AutoSave) { CurrentSchema.Save(); } return(new SchemaResult("Key column set")); } catch (Exception ex) { return(GetErrorResult(ex)); } }
/// <summary> /// Add the specified column to the specified table. /// </summary> /// <param name="tableName"></param> /// <param name="column"></param> /// <returns></returns> public SchemaResult AddColumn(string tableName, Column column) { try { Table table = CurrentSchema.GetTable(tableName); table.AddColumn(column); if (AutoSave) { CurrentSchema.Save(); } return(new SchemaResult("column added")); } catch (Exception ex) { return(GetErrorResult(ex)); } }
/// <summary> /// Used to specify a different property name to use /// on generated Dao instead of the column name /// </summary> /// <param name="tableName"></param> /// <param name="columnName"></param> /// <param name="propertyName"></param> /// <returns></returns> public SchemaResult SetColumnPropertyName(string tableName, string columnName, string propertyName) { try { Table table = CurrentSchema.GetTable(tableName); table.SetPropertyName(columnName, propertyName); if (AutoSave) { CurrentSchema.Save(); } return(new SchemaResult("column property name set")); } catch (Exception ex) { return(GetErrorResult(ex)); } }
protected void SetForeignKeyClassNames() { CurrentSchema.Tables.Each(table => { ForeignKeyColumn[] referencingKeys = GetReferencingForeignKeysForTable(table.Name); referencingKeys.Each(fk => { fk.ReferencedClass = table.ClassName; }); ForeignKeyColumn[] fks = GetForeignKeysForTable(table.Name); fks.Each(fk => { fk.ReferencingClass = table.ClassName; fk.TableClassName = table.ClassName; }); if (AutoSave) { CurrentSchema.Save(); } }); }
internal static Fact Create(XbrlFragment ParentFragment, INode FactNode) { Fact FactToReturn = null; if ((IsXbrlNamespace(FactNode.NamespaceURI) == false) && (IsW3Namespace(FactNode.NamespaceURI) == false) && (FactNode.IsComment == false)) { // This item could be a fact, or it could be a tuple. Examine the schemas // to find out what we're dealing with. Element MatchingElement = null; foreach (var CurrentSchema in ParentFragment.Schemas) { var FoundElement = CurrentSchema.GetElement(FactNode.LocalName); if (FoundElement != null) { MatchingElement = FoundElement; } } if (MatchingElement != null) { switch (MatchingElement.SubstitutionGroup) { case Element.ElementSubstitutionGroup.Item: FactToReturn = new Item(ParentFragment, FactNode); break; case Element.ElementSubstitutionGroup.Tuple: FactToReturn = new Tuple(ParentFragment, FactNode); break; default: // This type is unknown, so leave it alone. break; } } } return(FactToReturn); }
public SchemaResult SetTableClassName(string tableName, string className) { try { Table table = CurrentSchema.GetTable(tableName); table.ClassName = className; table.Columns.Each(col => { col.TableClassName = className; }); SetForeignKeyClassNames(); if (AutoSave) { CurrentSchema.Save(); } return(new SchemaResult("class name set")); } catch (Exception ex) { return(GetErrorResult(ex)); } }
private async Task <DatabaseSchema> Load(bool forceReload, CancellationToken cancellationToken) { Instant requested = TimeHelpers.Clock.Now; using (await _lock.LockAsync(cancellationToken).ConfigureAwait(false)) { // Check to see if the currently loaded schema is acceptable. CurrentSchema current = _current; // ReSharper disable once ConditionIsAlwaysTrueOrFalse if ((current != null) && (!forceReload || (current.Loaded > requested))) { // Rethrow load errors. if (current.ExceptionDispatchInfo != null) { current.ExceptionDispatchInfo.Throw(); } Debug.Assert(current.Schema != null); return(this); } // Create dictionaries Dictionary <int, SqlSchema> sqlSchemas = new Dictionary <int, SqlSchema>(); Dictionary <int, SqlType> typesByID = new Dictionary <int, SqlType>(); Dictionary <string, SqlType> typesByName = new Dictionary <string, SqlType>(StringComparer.InvariantCultureIgnoreCase); Dictionary <string, SqlProgramDefinition> programDefinitions = new Dictionary <string, SqlProgramDefinition>(StringComparer.InvariantCultureIgnoreCase); Dictionary <string, SqlTableDefinition> tables = new Dictionary <string, SqlTableDefinition>(StringComparer.InvariantCultureIgnoreCase); try { // Open a connection using (SqlConnection sqlConnection = new SqlConnection(ConnectionString)) { // ReSharper disable once PossibleNullReferenceException await sqlConnection.OpenAsync(cancellationToken).ConfigureAwait(false); Version version; if (!Version.TryParse(sqlConnection.ServerVersion, out version)) { throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_CouldNotParseVersionInformation); } Debug.Assert(version != null); if (version.Major < 9) { throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_VersionNotSupported, version); } string sql = version.Major == 9 ? SQLResources.RetrieveSchema9 : SQLResources.RetrieveSchema10; // Create the command first, as we will reuse on each connection. using ( SqlCommand command = new SqlCommand(sql, sqlConnection) { CommandType = CommandType.Text }) // Execute command using (SqlDataReader reader = // ReSharper disable once PossibleNullReferenceException await command.ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken) .ConfigureAwait(false)) { /* * Load SQL Schemas */ while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) { SqlSchema sqlSchema = new SqlSchema(reader.GetInt32(0), reader.GetString(1)); sqlSchemas.Add(sqlSchema.ID, sqlSchema); } if (sqlSchemas.Count < 1) { throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_CouldNotRetrieveSchemas); } /* * Load types */ if (!(await reader.NextResultAsync(cancellationToken).ConfigureAwait(false))) { throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_RanOutOfResultsRetrievingTypes); } while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) { int schemaId = reader.GetInt32(0); SqlSchema sqlSchema; if (!sqlSchemas.TryGetValue(schemaId, out sqlSchema) || (sqlSchema == null)) { throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_CouldNotFindSchema, schemaId); } int id = reader.GetInt32(1); string name = reader.GetString(2).ToLower(); SqlType baseType; if (reader.IsDBNull(3)) { baseType = null; } else { // NB SQL returns types in dependency order // i.e. base types are always seen first, so this code is much easier. int baseId = reader.GetInt32(3); typesByID.TryGetValue(baseId, out baseType); } short maxLength = reader.GetInt16(4); byte precision = reader.GetByte(5); byte scale = reader.GetByte(6); bool isNullable = reader.GetBoolean(7); bool isUserDefined = reader.GetBoolean(8); bool isCLR = reader.GetBoolean(9); bool isTable = reader.GetBoolean(10); // Create type SqlType type = isTable ? new SqlTableType( baseType, sqlSchema, name, new SqlTypeSize(maxLength, precision, scale), isNullable, isUserDefined, isCLR) : new SqlType( baseType, sqlSchema, name, new SqlTypeSize(maxLength, precision, scale), isNullable, isUserDefined, isCLR); // Add to dictionary typesByName.Add(type.FullName, type); if (!typesByName.ContainsKey(type.Name)) { typesByName.Add(type.Name, type); } typesByID.Add(id, type); } if (typesByName.Count < 1) { throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_CouldNotRetrieveTypes); } /* * Load program definitions */ if (!(await reader.NextResultAsync(cancellationToken).ConfigureAwait(false))) { throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_RanOutOfResultsRetrievingPrograms); } List <ProgramDefinitionData> programDefinitionData = new List <ProgramDefinitionData>(); while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) { SqlObjectType type; string typeString = reader.GetString(0) ?? string.Empty; if (!ExtendedEnum <SqlObjectType> .TryParse(typeString, true, out type)) { throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_CouldNotFindTypeWhenLoadingPrograms, typeString); } int schemaId = reader.GetInt32(1); SqlSchema sqlSchema; if (!sqlSchemas.TryGetValue(schemaId, out sqlSchema)) { throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_CouldNotFindSchemaWhenLoadingPrograms, schemaId); } string name = reader.GetString(2).ToLower(); // If we have a null ordinal, we have no parameters. if (reader.IsDBNull(3)) { programDefinitionData.Add(new ProgramDefinitionData(type, schemaId, name)); continue; } int ordinal = reader.GetInt32(3); string parameterName = reader.GetString(4).ToLower(); int typeId = reader.GetInt32(5); SqlType parameterType; if (!typesByID.TryGetValue(typeId, out parameterType) || (parameterType == null)) { throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_ParameterTypeNotFound, parameterName, typeId, name); } short maxLength = reader.GetInt16(6); byte precision = reader.GetByte(7); byte scale = reader.GetByte(8); SqlTypeSize parameterSize = new SqlTypeSize(maxLength, precision, scale); bool isOutput = reader.GetBoolean(9); ParameterDirection parameterDirection; if (!isOutput) { parameterDirection = ParameterDirection.Input; } else if (parameterName == string.Empty) { parameterDirection = ParameterDirection.ReturnValue; } else { parameterDirection = ParameterDirection.InputOutput; } bool parameterIsReadOnly = reader.GetBoolean(10); programDefinitionData.Add( new ProgramDefinitionData( type, schemaId, name, ordinal, parameterName, parameterType, parameterSize, parameterDirection, parameterIsReadOnly)); } // Create unique program definitions. foreach (SqlProgramDefinition program in programDefinitionData // ReSharper disable once PossibleNullReferenceException .GroupBy(d => d.ToString()) .Select( g => { Debug.Assert(g != null); // Get columns ordered by ordinal. SqlProgramParameter[] parameters = g // ReSharper disable once PossibleNullReferenceException .Select(d => d.Parameter) .Where(p => p != null) .OrderBy(p => p.Ordinal) .ToArray(); ProgramDefinitionData first = g.First(); Debug.Assert(first != null); Debug.Assert(first.Name != null); Debug.Assert(sqlSchemas != null); SqlSchema sqlSchema; if (!sqlSchemas.TryGetValue(first.SchemaID, out sqlSchema)) { throw new DatabaseSchemaException( () => Resources .DatabaseSchema_Load_CouldNotFindSchemaLoadingTablesAndViews, first.SchemaID); } Debug.Assert(sqlSchema != null); return(new SqlProgramDefinition( first.Type, sqlSchema, first.Name, parameters)); })) { Debug.Assert(program != null); programDefinitions[program.FullName] = program; if (!programDefinitions.ContainsKey(program.Name)) { programDefinitions.Add(program.Name, program); } } /* * Load tables and views */ if (!(await reader.NextResultAsync(cancellationToken).ConfigureAwait(false))) { throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_RanOutOfTablesAndViews); } // Read raw data in. List <TableDefinitionData> tableDefinitionData = new List <TableDefinitionData>(); while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) { SqlObjectType type; string typeString = reader.GetString(0) ?? string.Empty; if (!ExtendedEnum <SqlObjectType> .TryParse(typeString, true, out type)) { throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_CouldNotFindObjectType, typeString); } int schemaId = reader.GetInt32(1); string name = reader.GetString(2).ToLower(); int ordinal = reader.GetInt32(3); string columnName = reader.GetString(4).ToLower(); int typeId = reader.GetInt32(5); SqlType sqlType; if (!typesByID.TryGetValue(typeId, out sqlType) || (sqlType == null)) { throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_ColumnTypeNotFound, columnName, typeId, name); } short maxLength = reader.GetInt16(6); byte precision = reader.GetByte(7); byte scale = reader.GetByte(8); SqlTypeSize sqlTypeSize = new SqlTypeSize(maxLength, precision, scale); bool isNullable = reader.GetBoolean(9); int?tableType = reader.IsDBNull(10) ? null : (int?)reader.GetInt32(10); tableDefinitionData.Add( new TableDefinitionData( type, schemaId, name, ordinal, columnName, sqlType, sqlTypeSize, isNullable, tableType)); } // Create unique table definitions. foreach (SqlTableDefinition table in tableDefinitionData // ReSharper disable once PossibleNullReferenceException .GroupBy(d => d.ToString()) .Select( g => { Debug.Assert(g != null); // Get columns ordered by ordinal. SqlColumn[] columns = g // ReSharper disable PossibleNullReferenceException .Select(d => d.Column) .OrderBy(c => c.Ordinal) // ReSharper restore PossibleNullReferenceException .ToArray(); Debug.Assert(columns.Length > 0); TableDefinitionData first = g.First(); Debug.Assert(first != null); Debug.Assert(first.Name != null); Debug.Assert(sqlSchemas != null); SqlSchema sqlSchema; if (!sqlSchemas.TryGetValue(first.SchemaID, out sqlSchema)) { throw new DatabaseSchemaException( () => Resources .DatabaseSchema_Load_CouldNotFindSchemaLoadingTablesAndViews, first.SchemaID); } Debug.Assert(sqlSchema != null); SqlTableType tableType; if (first.TableTypeID != null) { Debug.Assert(typesByID != null); SqlType tType; if (!typesByID.TryGetValue(first.TableTypeID.Value, out tType)) { throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_TableTypeNotFound, first.TableTypeID.Value, first.Name); } tableType = tType as SqlTableType; if (tableType == null) { throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_TypeNotTableType, first.TableTypeID.Value, first.Name); } } else { tableType = null; } return(new SqlTableDefinition( first.Type, sqlSchema, first.Name, columns, tableType)); })) { Debug.Assert(table != null); tables[table.FullName] = table; if (!tables.ContainsKey(table.Name)) { tables.Add(table.Name, table); } } } } // Update the current schema. _current = new CurrentSchema(Schema.GetOrAdd(sqlSchemas, programDefinitions, tables, typesByName)); // Always return this return(this); } // In the event of an error we don't set the loaded flag - this allows retries. catch (DatabaseSchemaException databaseSchemaException) { // Capture the exception in the current schema. _current = new CurrentSchema(ExceptionDispatchInfo.Capture(databaseSchemaException)); throw; } catch (Exception exception) { // Wrap exception in Database exception. DatabaseSchemaException databaseSchemaException = new DatabaseSchemaException( exception, LoggingLevel.Critical, () => Resources.DatabaseSchema_Load_ErrorOccurred); // Capture the exception in the current schema. _current = new CurrentSchema(ExceptionDispatchInfo.Capture(databaseSchemaException)); throw databaseSchemaException; } } }
public Table GetTable(string tableName) { return(CurrentSchema.GetTable(tableName)); }
public XrefTable GetXref(string tableName) { return(CurrentSchema.GetXref(tableName)); }
public void RemoveTable(string tableName) { CurrentSchema.RemoveTable(tableName); }
private async Task<DatabaseSchema> Load(bool forceReload, CancellationToken cancellationToken) { Instant requested = TimeHelpers.Clock.Now; using (await _lock.LockAsync(cancellationToken).ConfigureAwait(false)) { // Check to see if the currently loaded schema is acceptable. CurrentSchema current = _current; // ReSharper disable once ConditionIsAlwaysTrueOrFalse if ((current != null) && (!forceReload || (current.Loaded > requested))) { // Rethrow load errors. if (current.ExceptionDispatchInfo != null) current.ExceptionDispatchInfo.Throw(); Debug.Assert(current.Schema != null); return this; } // Create dictionaries Dictionary<int, SqlSchema> sqlSchemas = new Dictionary<int, SqlSchema>(); Dictionary<int, SqlType> typesByID = new Dictionary<int, SqlType>(); Dictionary<string, SqlType> typesByName = new Dictionary<string, SqlType>(StringComparer.InvariantCultureIgnoreCase); Dictionary<string, SqlProgramDefinition> programDefinitions = new Dictionary<string, SqlProgramDefinition>(StringComparer.InvariantCultureIgnoreCase); Dictionary<string, SqlTableDefinition> tables = new Dictionary<string, SqlTableDefinition>(StringComparer.InvariantCultureIgnoreCase); try { // Open a connection using (SqlConnection sqlConnection = new SqlConnection(ConnectionString)) { // ReSharper disable once PossibleNullReferenceException await sqlConnection.OpenAsync(cancellationToken).ConfigureAwait(false); Version version; if (!Version.TryParse(sqlConnection.ServerVersion, out version)) throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_CouldNotParseVersionInformation); Debug.Assert(version != null); if (version.Major < 9) throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_VersionNotSupported, version); string sql = version.Major == 9 ? SQLResources.RetrieveSchema9 : SQLResources.RetrieveSchema10; // Create the command first, as we will reuse on each connection. using ( SqlCommand command = new SqlCommand(sql, sqlConnection) { CommandType = CommandType.Text }) // Execute command using (SqlDataReader reader = // ReSharper disable once PossibleNullReferenceException await command.ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellationToken) .ConfigureAwait(false)) { /* * Load SQL Schemas */ while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) { SqlSchema sqlSchema = new SqlSchema(reader.GetInt32(0), reader.GetString(1)); sqlSchemas.Add(sqlSchema.ID, sqlSchema); } if (sqlSchemas.Count < 1) throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_CouldNotRetrieveSchemas); /* * Load types */ if (!(await reader.NextResultAsync(cancellationToken).ConfigureAwait(false))) throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_RanOutOfResultsRetrievingTypes); while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) { int schemaId = reader.GetInt32(0); SqlSchema sqlSchema; if (!sqlSchemas.TryGetValue(schemaId, out sqlSchema) || (sqlSchema == null)) throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_CouldNotFindSchema, schemaId); int id = reader.GetInt32(1); string name = reader.GetString(2).ToLower(); SqlType baseType; if (reader.IsDBNull(3)) baseType = null; else { // NB SQL returns types in dependency order // i.e. base types are always seen first, so this code is much easier. int baseId = reader.GetInt32(3); typesByID.TryGetValue(baseId, out baseType); } short maxLength = reader.GetInt16(4); byte precision = reader.GetByte(5); byte scale = reader.GetByte(6); bool isNullable = reader.GetBoolean(7); bool isUserDefined = reader.GetBoolean(8); bool isCLR = reader.GetBoolean(9); bool isTable = reader.GetBoolean(10); // Create type SqlType type = isTable ? new SqlTableType( baseType, sqlSchema, name, new SqlTypeSize(maxLength, precision, scale), isNullable, isUserDefined, isCLR) : new SqlType( baseType, sqlSchema, name, new SqlTypeSize(maxLength, precision, scale), isNullable, isUserDefined, isCLR); // Add to dictionary typesByName.Add(type.FullName, type); if (!typesByName.ContainsKey(type.Name)) typesByName.Add(type.Name, type); typesByID.Add(id, type); } if (typesByName.Count < 1) throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_CouldNotRetrieveTypes); /* * Load program definitions */ if (!(await reader.NextResultAsync(cancellationToken).ConfigureAwait(false))) throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_RanOutOfResultsRetrievingPrograms); List<ProgramDefinitionData> programDefinitionData = new List<ProgramDefinitionData>(); while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) { SqlObjectType type; string typeString = reader.GetString(0) ?? string.Empty; if (!ExtendedEnum<SqlObjectType>.TryParse(typeString, true, out type)) throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_CouldNotFindTypeWhenLoadingPrograms, typeString); int schemaId = reader.GetInt32(1); SqlSchema sqlSchema; if (!sqlSchemas.TryGetValue(schemaId, out sqlSchema)) throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_CouldNotFindSchemaWhenLoadingPrograms, schemaId); string name = reader.GetString(2).ToLower(); // If we have a null ordinal, we have no parameters. if (reader.IsDBNull(3)) { programDefinitionData.Add(new ProgramDefinitionData(type, schemaId, name)); continue; } int ordinal = reader.GetInt32(3); string parameterName = reader.GetString(4).ToLower(); int typeId = reader.GetInt32(5); SqlType parameterType; if (!typesByID.TryGetValue(typeId, out parameterType) || (parameterType == null)) throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_ParameterTypeNotFound, parameterName, typeId, name); short maxLength = reader.GetInt16(6); byte precision = reader.GetByte(7); byte scale = reader.GetByte(8); SqlTypeSize parameterSize = new SqlTypeSize(maxLength, precision, scale); bool isOutput = reader.GetBoolean(9); ParameterDirection parameterDirection; if (!isOutput) parameterDirection = ParameterDirection.Input; else if (parameterName == string.Empty) parameterDirection = ParameterDirection.ReturnValue; else parameterDirection = ParameterDirection.InputOutput; bool parameterIsReadOnly = reader.GetBoolean(10); programDefinitionData.Add( new ProgramDefinitionData( type, schemaId, name, ordinal, parameterName, parameterType, parameterSize, parameterDirection, parameterIsReadOnly)); } // Create unique program definitions. foreach (SqlProgramDefinition program in programDefinitionData // ReSharper disable once PossibleNullReferenceException .GroupBy(d => d.ToString()) .Select( g => { Debug.Assert(g != null); // Get columns ordered by ordinal. SqlProgramParameter[] parameters = g // ReSharper disable once PossibleNullReferenceException .Select(d => d.Parameter) .Where(p => p != null) .OrderBy(p => p.Ordinal) .ToArray(); ProgramDefinitionData first = g.First(); Debug.Assert(first != null); Debug.Assert(first.Name != null); Debug.Assert(sqlSchemas != null); SqlSchema sqlSchema; if (!sqlSchemas.TryGetValue(first.SchemaID, out sqlSchema)) throw new DatabaseSchemaException( () => Resources .DatabaseSchema_Load_CouldNotFindSchemaLoadingTablesAndViews, first.SchemaID); Debug.Assert(sqlSchema != null); return new SqlProgramDefinition( first.Type, sqlSchema, first.Name, parameters); })) { Debug.Assert(program != null); programDefinitions[program.FullName] = program; if (!programDefinitions.ContainsKey(program.Name)) programDefinitions.Add(program.Name, program); } /* * Load tables and views */ if (!(await reader.NextResultAsync(cancellationToken).ConfigureAwait(false))) throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_RanOutOfTablesAndViews); // Read raw data in. List<TableDefinitionData> tableDefinitionData = new List<TableDefinitionData>(); while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) { SqlObjectType type; string typeString = reader.GetString(0) ?? string.Empty; if (!ExtendedEnum<SqlObjectType>.TryParse(typeString, true, out type)) throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_CouldNotFindObjectType, typeString); int schemaId = reader.GetInt32(1); string name = reader.GetString(2).ToLower(); int ordinal = reader.GetInt32(3); string columnName = reader.GetString(4).ToLower(); int typeId = reader.GetInt32(5); SqlType sqlType; if (!typesByID.TryGetValue(typeId, out sqlType) || (sqlType == null)) throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_ColumnTypeNotFound, columnName, typeId, name); short maxLength = reader.GetInt16(6); byte precision = reader.GetByte(7); byte scale = reader.GetByte(8); SqlTypeSize sqlTypeSize = new SqlTypeSize(maxLength, precision, scale); bool isNullable = reader.GetBoolean(9); int? tableType = reader.IsDBNull(10) ? null : (int?)reader.GetInt32(10); tableDefinitionData.Add( new TableDefinitionData( type, schemaId, name, ordinal, columnName, sqlType, sqlTypeSize, isNullable, tableType)); } // Create unique table definitions. foreach (SqlTableDefinition table in tableDefinitionData // ReSharper disable once PossibleNullReferenceException .GroupBy(d => d.ToString()) .Select( g => { Debug.Assert(g != null); // Get columns ordered by ordinal. SqlColumn[] columns = g // ReSharper disable PossibleNullReferenceException .Select(d => d.Column) .OrderBy(c => c.Ordinal) // ReSharper restore PossibleNullReferenceException .ToArray(); Debug.Assert(columns.Length > 0); TableDefinitionData first = g.First(); Debug.Assert(first != null); Debug.Assert(first.Name != null); Debug.Assert(sqlSchemas != null); SqlSchema sqlSchema; if (!sqlSchemas.TryGetValue(first.SchemaID, out sqlSchema)) throw new DatabaseSchemaException( () => Resources .DatabaseSchema_Load_CouldNotFindSchemaLoadingTablesAndViews, first.SchemaID); Debug.Assert(sqlSchema != null); SqlTableType tableType; if (first.TableTypeID != null) { Debug.Assert(typesByID != null); SqlType tType; if (!typesByID.TryGetValue(first.TableTypeID.Value, out tType)) throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_TableTypeNotFound, first.TableTypeID.Value, first.Name); tableType = tType as SqlTableType; if (tableType == null) throw new DatabaseSchemaException( () => Resources.DatabaseSchema_Load_TypeNotTableType, first.TableTypeID.Value, first.Name); } else tableType = null; return new SqlTableDefinition( first.Type, sqlSchema, first.Name, columns, tableType); })) { Debug.Assert(table != null); tables[table.FullName] = table; if (!tables.ContainsKey(table.Name)) tables.Add(table.Name, table); } } } // Update the current schema. _current = new CurrentSchema(Schema.GetOrAdd(sqlSchemas, programDefinitions, tables, typesByName)); // Always return this return this; } // In the event of an error we don't set the loaded flag - this allows retries. catch (DatabaseSchemaException databaseSchemaException) { // Capture the exception in the current schema. _current = new CurrentSchema(ExceptionDispatchInfo.Capture(databaseSchemaException)); throw; } catch (Exception exception) { // Wrap exception in Database exception. DatabaseSchemaException databaseSchemaException = new DatabaseSchemaException( exception, LoggingLevel.Critical, () => Resources.DatabaseSchema_Load_ErrorOccurred); // Capture the exception in the current schema. _current = new CurrentSchema(ExceptionDispatchInfo.Capture(databaseSchemaException)); throw databaseSchemaException; } } }