protected void GetIdentityInformation( TableMap map ) { if( map != null ) { // also obtain identity column information GentleSqlFactory sf = provider.GetSqlFactory(); try { string tableName = sf.GetTableName( map.TableName ); foreach( FieldMap fm in map.Fields ) { if( fm.IsPrimaryKey ) { if( ! map.IsView ) { SqlResult sr = broker.Execute( String.Format( selectIdentityInfo, tableName, fm.ColumnName ) ); fm.SetIsAutoGenerated( sr.GetInt( 0, "IsIdentity" ) == 1 ); } } } } catch( Exception e ) { Check.LogWarning( LogCategories.Metadata, "Unable to determine whether PK column of table {0} is an identity column.", map.TableName ); Check.LogWarning( LogCategories.Metadata, e.Message ); } } }
public override void Analyze( string tableName ) { try { bool isSingleRun = tableName != null; SqlStatement stmt = broker.GetStatement( selectTables ); stmt.StatementType = StatementType.Select; SqlResult sr = stmt.Execute(); for( int i = 0; i < sr.Rows.Count; i++ ) { try { string dbTableName = sr.GetString( i, 0 ); if( ! isSingleRun || tableName.ToLower().Equals( dbTableName.ToLower() ) ) { TableMap map = GetTableMap( dbTableName ); if( map == null ) { map = new TableMap( provider, dbTableName ); maps[ dbTableName.ToLower() ] = map; } // TODO: get column information for this table // TODO: get foreign key information // abort loop if analyzing single table only if( isSingleRun ) { break; } } } catch( GentleException fe ) { // ignore errors caused by tables found in db but for which no map exists // TODO this should be a config option if( fe.Error != Error.NoObjectMapForTable ) { throw fe; } } } } catch( Exception e ) { Check.Fail( e, Error.Unspecified, "An error occurred while analyzing the database schema." ); } }
/// <summary> /// Please refer to the <see cref="GentleAnalyzer"/> class and the <see cref="IDatabaseAnalyzer"/> /// interface it implements a description of this method. /// </summary> public override void Analyze( string tableName ) { GentleSqlFactory sf = provider.GetSqlFactory(); try { bool isSingleRun = tableName != null; string sql = isSingleRun ? String.Format( "{0} and name = '{1}'", selectTables, tableName ) : selectTables; SqlResult sr = broker.Execute( sql, null, null ); for( int row=0; row<sr.RowsContained; row++ ) { tableName = sr.GetString( row, 0 ); // get TableMap for current table TableMap map = GetTableMap( tableName ); if( map == null ) { map = new TableMap( provider, tableName ); maps[ tableName.ToLower() ] = map; } // get column information UpdateTableMapWithColumnInformation( map ); // get foreign key information UpdateTableMapWithForeignKeyInformation( map ); } } catch( GentleException fe ) { // ignore errors caused by tables found in db but for which no map exists // TODO this should be a config option if( fe.Error != Error.NoObjectMapForTable ) { throw; } } catch( Exception e ) { Check.LogInfo( LogCategories.General, "Using provider {0} and connectionString {1}.", provider.Name, provider.ConnectionString ); Check.Fail( e, Error.Unspecified, "An error occurred while analyzing the database schema." ); } }
/// <summary> /// Obtain a list of <see cref="FieldMap"/> instances that represent foreign key /// references to fields on the supplied parent object. /// </summary> /// <param name="parentMap">The map of the type the foreign key fields should reference /// if they are to be included in the result.</param> /// <param name="isPrimaryKeysOnly">True if only foreign keys pointing to primary keys /// should be included, false to include all foreign key references.</param> /// <returns>A list of FieldMap instances or an empty list id no fields matched.</returns> public Hashtable GetForeignKeyMappings( TableMap parentMap, bool isPrimaryKeysOnly ) { Hashtable result = new Hashtable(); foreach( FieldMap child in fields ) { if( child.IsForeignKey ) { foreach( FieldMap parent in parentMap.Fields ) { bool isSameTable = String.Compare( child.ForeignKeyTableName, parentMap.TableName, true ) == 0; isSameTable |= String.Compare( child.ForeignKeyTableName, parentMap.QuotedTableName, true ) == 0; if( isSameTable && String.Compare( child.ForeignKeyColumnName, parent.ColumnName, true ) == 0 ) { bool isPK = child.IsPrimaryKey || parent.IsPrimaryKey; if( ! isPrimaryKeysOnly || (isPrimaryKeysOnly && isPK) ) { result[ child ] = parent; } } } } } Check.Verify( result.Count > 0, Error.DeveloperError, String.Format( "The table {0} has no foreign keys pointing to table {1}.", tableName, parentMap.TableName ) ); return result; }
/// <summary> /// Please refer to the <see cref="GentleAnalyzer"/> class and the <see cref="IDatabaseAnalyzer"/> /// interface it implements a description of this method. /// </summary> public override void Analyze( string tableName ) { GentleSqlFactory sf = provider.GetSqlFactory(); try { bool isSingleRun = tableName != null; // don't quote reserved words here (table name is just a string parameter) string sql = isSingleRun ? select + String.Format( selectSingle, tableName ) : select; SqlResult sr = broker.Execute( sql, null, null ); // process result set using columns: // TableName, ColumnName, Type, Size, IsNullable, DefaultValue, // ConstraintName, ConstraintReference, ConstraintType, // UpdateRule, DeleteRule, TableType for( int i = 0; i < sr.Rows.Count; i++ ) { try { string dbTableName = sr.GetString( i, "tablename" ); if( ! isSingleRun || tableName.ToLower().Equals( dbTableName.ToLower() ) ) { TableMap map = GetTableMap( dbTableName ); if( map == null ) { map = new TableMap( provider, dbTableName ); maps[ dbTableName.ToLower() ] = map; } map.IsView = sr.GetString( i, "TableType" ) == "VIEW"; // get column information for this table string columnName = sr.GetString( i, "ColumnName" ); FieldMap fm = map.GetFieldMapFromColumn( columnName ); if( fm == null ) { fm = new FieldMap( map, columnName ); map.Fields.Add( fm ); } // get basic column information fm.SetDbType( sr.GetString( i, "Type" ), false ); // sql server is always false fm.SetIsNullable( GetBoolean( sr.GetString( i, "IsNullable" ) ) ); fm.SetIsAutoGenerated( sr.GetString( i, "DefaultValue" ).Length > 0 ? true : false ); if( sr[ i, "Size" ] != null && fm.DbType != (long) SqlDbType.Text ) { fm.SetSize( sr.GetInt( i, "Size" ) ); } // get column constraint infomation if( sr[ i, "ConstraintName" ] != null ) { string type = sr.GetString( i, "ConstraintType" ); if( type.ToLower().Equals( "primary key" ) ) { fm.SetIsPrimaryKey( true ); } else if( type.ToLower().Equals( "foreign key" ) ) { string conref = sr.GetString( i, "ConstraintReference" ); if( conref.StartsWith( "IDX" ) ) { string fkRef = sr.GetString( i, "ConstraintName" ); if( fkRef != null && fkRef.StartsWith( "FK" ) ) { conref = fkRef; } } SqlResult res = broker.Execute( String.Format( selectReferences, conref ), null, null ); if( res.ErrorCode == 0 && res.RowsContained == 1 ) { fm.SetForeignKeyTableName( res.GetString( 0, "TableName" ) ); fm.SetForeignKeyColumnName( res.GetString( 0, "ColumnName" ) ); } else { if( res.RowsContained == 0 ) { // see GOPF-155 for additional information Check.LogWarning( LogCategories.Metadata, "Unable to obtain foreign key information for column {0} of table {1}.", fm.ColumnName, map.TableName ); } else { Check.LogWarning( LogCategories.Metadata, "Gentle 1.x does not support composite foreign keys." ); } } } } if( map.IsView ) { // TODO // process backing table members and infer PK/identity info // requires that tables be processed before views! // //string sv = String.Format( selectViewDependencies, map.TableName ); //SqlResult res = broker.Execute( sv ); } } } catch( GentleException fe ) { // ignore errors caused by tables found in db but for which no map exists // TODO this should be a config option if( fe.Error != Error.NoObjectMapForTable ) { throw; } } } } catch( Exception e ) { Check.LogInfo( LogCategories.General, "Using provider {0} and connectionString {1}.", provider.Name, provider.ConnectionString ); Check.Fail( e, Error.Unspecified, "An error occurred while analyzing the database schema." ); } }
public override void Analyze( string tableName ) { GentleSqlFactory sf = provider.GetSqlFactory(); try { bool isSingleRun = tableName != null; // Create foreign key statement SqlStatement fk = broker.GetStatement( StatementType.Select, selectReferences ); sf.AddParameter( fk.Command, "TableName", (long) FbDbType.VarChar ); sf.AddParameter( fk.Command, "ColumnName", (long) FbDbType.VarChar ); // Get tables information SqlResult sr = broker.Execute( select ); // process result set for( int i = 0; i < sr.Rows.Count; i++ ) { try { string dbTableName = sr.GetString( i, "TableName" ).Trim(); if( ! isSingleRun || tableName.ToLower().Equals( dbTableName.ToLower() ) ) { TableMap map = GetTableMap( dbTableName ); if( map == null ) { map = new TableMap( provider, dbTableName ); maps[ dbTableName.ToLower() ] = map; } // get column information for this table string columnName = sr.GetString( i, "ColumnName" ).Trim(); FieldMap fm = map.GetFieldMapFromColumn( columnName ); if( fm == null ) { fm = new FieldMap( map, columnName ); map.Fields.Add( fm ); } FbDbType type = GetFbDbType( sr.GetInt( i, "ColumnDataType" ), sr[ i, "ColumnSubType" ] != null ? sr.GetInt( i, "ColumnSubType" ) : 0, sr[ i, "ColumnScale" ] != null ? sr.GetInt( i, "ColumnScale" ) : 0 ); fm.SetDbType( (long) type ); if( sr[ i, "NullFlag" ] == null ) { fm.SetIsNullable( true ); } else { fm.SetIsNullable( false ); } if( sr[ i, "ColumnSize" ] != null ) { switch( type ) { case FbDbType.Binary: case FbDbType.Text: fm.SetSize( Int32.MaxValue ); break; default: fm.SetSize( sr.GetInt( i, "ColumnSize" ) ); break; } } if( sr.GetInt( i, "PrimaryKey" ) > 0 ) { fm.SetIsPrimaryKey( true ); } if( sr.GetInt( i, "ForeignKey" ) > 0 ) { fk.SetParameter( "TableName", map.TableName.ToUpper() ); fk.SetParameter( "ColumnName", columnName.ToUpper() ); SqlResult res = fk.Execute(); fm.SetForeignKeyTableName( res.GetString( 0, "FKTableName" ).Trim() ); fm.SetForeignKeyColumnName( res.GetString( 0, "FKColumnName" ).Trim() ); } } } catch( GentleException fe ) { // ignore errors caused by tables found in db but for which no map exists // TODO this should be a config option if( fe.Error != Error.NoObjectMapForTable ) { throw fe; } } } } catch( Exception e ) { Check.Fail( e, Error.Unspecified, "An error occurred while analyzing the database schema." ); } }
private void GetColumnData( TableMap map ) { string sql = String.Format( selectColumns, map.TableId ); SqlResult sr = broker.Execute( sql ); for( int i = 0; i < sr.Rows.Count; i++ ) { string column = sr.GetString( i, "column_name" ); FieldMap fm = map.GetFieldMapFromColumn( column ); bool isNullable = sr.GetString( i, "nulls" ).Equals( "Y" ); if( fm != null ) { fm.ColumnId = sr.GetInt( i, "column_id" ); fm.SetDbType( sr.GetString( i, "domain_name" ), false ); fm.SetIsNullable( isNullable ); fm.SetSize( sr.GetInt( i, "width" ) ); } else // raise an error if we've detected a database/type mismatch { // TODO disabled due to code restructuring // Check.Verify( isNullable, Error.NoPropertyForNotNullColumn, column, map.Type ); } } }
private void GetColumnConstraints( TableMap map ) { // primary key string sql = String.Format( selectPrimaryKeyConstraints, map.TableId ); SqlResult sr = broker.Execute( sql ); if( sr.Rows.Count > 0 ) { int columnId = sr.GetInt( 0, "column_id" ); FieldMap fm = map.Fields.FindColumnById( columnId ); if( fm != null ) { fm.SetIsPrimaryKey( true ); } } // foreign key sql = String.Format( selectForeignKeyConstraints, map.TableId ); sr = broker.Execute( sql ); for( int i = 0; i < sr.Rows.Count; i++ ) { int columnId = sr.GetInt( i, "column_id" ); FieldMap fm = map.Fields.FindColumnById( columnId ); if( fm != null ) { fm.SetForeignKeyTableName( sr.GetString( i, "FT" ) ); fm.SetForeignKeyColumnName( sr.GetString( i, "FK" ) ); } } }
private void UpdateTableMapWithForeignKeyInformation( TableMap map ) { SqlResult sr = broker.Execute( String.Format( selectForeignKeys, map.TableName ), null, null ); // process result set using columns: ?? for( int i=0; i<sr.RowsContained; i++ ) { //string type = sr.GetString( i, "ConstraintType" ); //if( type.ToLower().Equals( "foreign key" ) ) //{ // string conref = sr.GetString( i, "ConstraintReference" ); // if( conref.StartsWith( "IDX" ) ) // { // string fkRef = sr.GetString( i, "ConstraintName" ); // if( fkRef != null && fkRef.StartsWith( "FK" ) ) // { // conref = fkRef; // } // } // SqlResult res = broker.Execute( String.Format( selectReferences, conref ), null, null ); // if( res.ErrorCode == 0 && res.RowsContained == 1 ) // { // fm.SetForeignKeyTableName( res.GetString( 0, "TableName" ) ); // fm.SetForeignKeyColumnName( res.GetString( 0, "ColumnName" ) ); // } // else // { // if( res.RowsContained == 0 ) // { // // see GOPF-155 for additional information // Check.LogWarning( LogCategories.Metadata, // "Unable to obtain foreign key information for column {0} of table {1}.", // fm.ColumnName, map.TableName ); // } // else // { // Check.LogWarning( LogCategories.Metadata, "Gentle 1.x does not support composite foreign keys." ); // } // } //} } }
/// <summary> /// Constructor for fields using information obtained from the TableColumn attribute. /// </summary> public FieldMap( ObjectMap map, MemberAttributeInfo memberAttributeInfo ) { this.map = map; memberInfo = memberAttributeInfo.MemberInfo; if( memberInfo is PropertyInfo ) { memberType = (memberInfo as PropertyInfo).PropertyType; } else { memberType = (memberInfo as FieldInfo).FieldType; } // extract information from attributes if( memberAttributeInfo.Attributes != null ) { foreach( Attribute attr in memberAttributeInfo.Attributes ) { if( attr is TableColumnAttribute ) { TableColumnAttribute tc = attr as TableColumnAttribute; SetColumnName( tc.Name ?? memberInfo.Name ); SetNullValue( tc.NullValue ); SetIsNullable( ! tc.NotNull ); SetSize( tc.Size ); if( tc.HasDbType ) { SetDbType( tc.DatabaseType ); } else { SetDbType( NO_DBTYPE ); } handleEnumAsString = tc.HandleEnumAsString; isReadOnly = tc.IsReadOnly; isUpdateAfterWrite = tc.IsUpdateAfterWrite; } else if( attr is PrimaryKeyAttribute ) { PrimaryKeyAttribute pk = attr as PrimaryKeyAttribute; SetIsPrimaryKey( true ); SetIsAutoGenerated( pk.AutoGenerated ); if( IsAutoGenerated ) { map.IdentityMap = this; } } else if( attr is ForeignKeyAttribute ) { ForeignKeyAttribute fk = attr as ForeignKeyAttribute; SetForeignKeyTableName( fk.ForeignTable ); SetForeignKeyColumnName( fk.ForeignColumn ); } else if( attr is ConcurrencyAttribute ) { ConcurrencyAttribute ca = attr as ConcurrencyAttribute; Check.Verify( memberType == typeof(int) || memberType == typeof(long), Error.DeveloperError, "Unsupported property type {0} for ConcurrencyAttribute {1}", memberInfo.ReflectedType, memberInfo.Name ); isConcurrencyColumn = true; map.ConcurrencyMap = this; } else if( attr is SoftDeleteAttribute ) { SoftDeleteAttribute sd = attr as SoftDeleteAttribute; Check.Verify( memberType == typeof(int) || memberType == typeof(long), Error.DeveloperError, "Unsupported property type {0} for SoftDeleteAttribute {1}", memberInfo.ReflectedType, memberInfo.Name ); isSoftDeleteColumn = true; map.SoftDeleteMap = this; } else if( attr is SequenceNameAttribute ) { // sequence name used when available (in place of name conventions or autodetected value) sequenceName = (attr as SequenceNameAttribute).Name; } else if( attr is InheritanceAttribute ) { // sequence name used when available (in place of name conventions or autodetected value) map.InheritanceMap = this; } } } }
/// <summary> /// Please refer to the <see cref="GentleAnalyzer"/> class and the <see cref="IDatabaseAnalyzer"/> /// interface it implements a description of this method. /// </summary> public override void Analyze( string tableName ) { try { bool isSingleRun = tableName != null; string selectSingle = isSingleRun ? String.Format( SELECT_SINGLE, tableName ) : String.Empty; // Check Oracle version and select appropriate SQL-Syntax SqlResult sr = broker.Execute( ORA_VERSION_SELECT ); // string ver = sr.GetString( 0, "Version" ).Substring( 0, 1 ); // int version = Convert.ToInt32( sr.GetString( 0, "Version" ).Substring( 0, 1 ) ); string ver = sr.GetString( 0, "Version" ); int indexOfDot = ver.IndexOf( "." ); if( indexOfDot < 0 ) { throw new GentleException( Error.DeveloperError, "Unable to determine Oracle database version." ); } int version = Convert.ToInt32( ver.Substring( 0, indexOfDot ) ); string select; string selectReferences; if( version < 9 ) { // If Oracle version == '8.1.6' use no-views selectReferences if( ver.Substring( 0, 5 ).CompareTo( "8.1.6" ) == 0 ) { selectReferences = ORA816_SELECT_REFERENCES; } else { selectReferences = ORA8_SELECT_REFERENCES; } select = ORA8_SELECT + selectSingle + ORDER_BY; } else { select = ORA9_SELECT + selectSingle + ORDER_BY; selectReferences = ORA9_SELECT_REFERENCES; } sr = broker.Execute( select ); // process result set using columns: // TableName, ColumnName, Type, Size, IsNullable, DefaultValue, // ConstraintName, ConstraintReference, ConstraintType, UpdateRule, DeleteRule for( int i = 0; i < sr.Rows.Count; i++ ) { try { string dbTableName = sr.GetString( i, "TableName" ); if( ! isSingleRun || tableName.ToLower().Equals( dbTableName.ToLower() ) ) { // get or create TableMap for table TableMap map = GetTableMap( dbTableName ); if( map == null ) { map = new TableMap( provider, dbTableName ); maps[ dbTableName.ToLower() ] = map; } // get or create FieldMap for column string columnName = sr.GetString( i, "ColumnName" ); FieldMap fm = map.GetFieldMapFromColumn( columnName ); if( fm == null ) { fm = new FieldMap( map, columnName ); map.Fields.Add( fm ); } // get basic column information fm.SetDbType( sr.GetString( i, "Type" ), false ); fm.SetIsNullable( GetBoolean( sr.GetString( i, "IsNullable" ) ) ); if( sr[ i, "Size" ] != null ) { if( fm.DbType == (long) OracleType.Clob ) { //Max 4GB //Preferred size 4294967296 fm.SetSize( int.MaxValue ); } else { fm.SetSize( sr.GetInt( i, "Size" ) ); } } // get column constraint infomation if( sr[ i, "ConstraintName" ] != null ) { string typ = sr.GetString( i, "ConstraintType" ); if( typ.ToLower().Equals( "p" ) ) { fm.SetIsPrimaryKey( true ); } else if( typ.ToLower().Equals( "r" ) ) { string conref = sr.GetString( i, "ConstraintReference" ); SqlResult res = broker.Execute( String.Format( selectReferences, conref ) ); fm.SetForeignKeyTableName( res.GetString( 0, "ChildTable" ) ); fm.SetForeignKeyColumnName( res.GetString( 0, "ChildColumn" ) ); } } } } catch( GentleException fe ) { // ignore errors caused by tables found in db but for which no map exists // TODO this should be a config option if( fe.Error != Error.NoObjectMapForTable ) { throw; } } } } catch( Exception e ) { Check.LogInfo( LogCategories.General, "Using provider {0} and connectionString {1}.", provider.Name, provider.ConnectionString ); Check.Fail( e, Error.Unspecified, "An error occurred while analyzing the database schema." ); } }
/// <summary> /// This method fills the TableMap with information on table columns. /// </summary> private void GetColumnData( TableMap map ) { DataTable dt = GetColumns( map.TableName ); foreach( DataRow row in dt.Rows ) { // result row contains: // COLUMN_NAME, DATA_TYPE, ORDINAL_POSITION, COLUMN_HASDEFAULT, COLUMN_DEFAULT, // COLUMN_FLAGS, IS_NULLABLE, NUMERIC_PRECISION, NUMERIC_SCALE, // CHARACTER_MAXIMUM_LENGTH, CHARACTER_OCTET_LENGTH string columnName = (string) row[ "COLUMN_NAME" ]; FieldMap fm = map.GetFieldMapFromColumn( columnName ); if( fm == null ) { fm = new FieldMap( map, columnName ); map.Fields.Add( fm ); } bool isNullable = Convert.ToBoolean( row[ "IS_NULLABLE" ] ); if( fm != null ) { OleDbType dbType = (OleDbType) row[ "DATA_TYPE" ]; fm.SetDbType( (long) dbType ); // set numeric scale for DBTYPE_DECIMAL, DBTYPE_NUMERIC, DBTYPE_VARNUMERIC if( dbType == OleDbType.Decimal || dbType == OleDbType.Numeric || dbType == OleDbType.VarNumeric ) { fm.SetSize( Convert.ToInt32( row[ "NUMERIC_PRECISION" ] ) ); } if( dbType == OleDbType.LongVarBinary || dbType == OleDbType.LongVarChar || dbType == OleDbType.LongVarWChar || dbType == OleDbType.VarBinary || dbType == OleDbType.VarChar || dbType == OleDbType.VarWChar || dbType == OleDbType.WChar || dbType == OleDbType.Char || dbType == OleDbType.BSTR || dbType == OleDbType.Binary ) { fm.SetSize( Convert.ToInt32( row[ "CHARACTER_MAXIMUM_LENGTH" ] ) ); } fm.SetIsNullable( isNullable ); int columnFlags = Convert.ToInt32( row[ "COLUMN_FLAGS" ] ); // BROKEN (expected value does not match IS_NULLABLE set above) // BROKEN set whether column can contain NULL values int flags = (int) DBCOLUMNFLAGS.ISNULLABLE + (int) DBCOLUMNFLAGS.MAYBENULL; bool isNullableFlag = (columnFlags & flags) != 0; //fm.SetIsNullable( isNullableFlag && fm.IsNullable ); // set whether column is updatable flags = (int) DBCOLUMNFLAGS.WRITE + (int) DBCOLUMNFLAGS.WRITEUNKNOWN; bool isReadOnly = (columnFlags & flags) == 0; fm.IsReadOnly = isReadOnly; // BROKEN (expected bitmask value is never set) // set whether column is auto-generated //flags = (int) DBCOLUMNFLAGS.ISROWID; //bool isAutoGenerated = (columnFlags & flags) != 0; //fm.SetIsAutoGenerated( isAutoGenerated ); } else // raise an error if we've detected a database/type mismatch { bool hasDefault = Convert.ToBoolean( row[ "COLUMN_HASDEFAULT" ] ); // TODO disabled due to code restructuring Check.Verify( isNullable || hasDefault, Error.NoPropertyForNotNullColumn, columnName, map.TableName ); } } }
private void GetColumnData( TableMap map ) { string sql = String.Format( selectColumns, map.TableId ); SqlResult sr = broker.Execute( sql ); for( int i = 0; i < sr.Rows.Count; i++ ) { string column = sr.GetString( i, "column_name" ); FieldMap fm = map.GetFieldMapFromColumn( column ); if( fm == null ) { fm = new FieldMap( map, column ); map.Fields.Add( fm ); } bool isNullable = sr.GetString( i, "nulls" ).Equals( "Y" ); bool isAutoGenerated = sr.GetString( i, "default" ).ToLower() == "autoincrement"; fm.ColumnId = sr.GetInt( i, "column_id" ); fm.SetDbType( sr.GetString( i, "domain_name" ), false ); fm.SetIsNullable( isNullable ); fm.SetIsAutoGenerated( isAutoGenerated ); fm.SetSize( sr.GetInt( i, "width" ) ); } }
/// <summary> /// This method updated the given ObjectMap instance with metadata obtained /// from the database. /// </summary> /// <param name="map">The ObjectMap to update</param> public virtual void UpdateObjectMap(ObjectMap map) { if (level != AnalyzerLevel.None) { TableMap dbMap = TableMaps[map.TableName.ToLower()] as TableMap; if (dbMap == null && level == AnalyzerLevel.OnDemand) { Analyze(map.TableName); dbMap = TableMaps[map.TableName.ToLower()] as TableMap; } Check.VerifyNotNull(dbMap, Error.UnknownTable, map.TableName, map.Type); // make sure table name is set map.Provider = provider; // transfer table information map.IsView = dbMap.IsView; bool isUseData = !map.IsView; isUseData |= map.IsView && HasCapability(ColumnInformation.IsView); // transfer column information IList processedFields = new ArrayList(map.Fields.Count); foreach (FieldMap dbfm in dbMap.Fields) { try { FieldMap fm = map.Fields.FindColumn(dbfm.ColumnName); if (fm != null) { // view information if (map.IsView) { if (HasCapability(ColumnInformation.ViewType)) { fm.SetDbType(dbfm.DbType); } if (HasCapability(ColumnInformation.ViewSize)) { fm.SetSize(dbfm.Size); } if (HasCapability(ColumnInformation.ViewIsNullable)) { fm.SetIsNullable(dbfm.IsNullable); } if (HasCapability(ColumnInformation.ViewIsPrimaryKey)) { fm.SetIsPrimaryKey(dbfm.IsPrimaryKey); } if (HasCapability(ColumnInformation.ViewIsAutoGenerated)) { fm.SetIsAutoGenerated(dbfm.IsAutoGenerated); } if (HasCapability(ColumnInformation.ViewIsForeignKey) && dbfm.IsForeignKey) { fm.SetForeignKeyTableName(dbfm.ForeignKeyTableName); fm.SetForeignKeyColumnName(dbfm.ForeignKeyColumnName); } } else // table information { if (HasCapability(ColumnInformation.TableType)) { fm.SetDbType(dbfm.DbType); } if (HasCapability(ColumnInformation.TableSize)) { fm.SetSize(dbfm.Size); } if (HasCapability(ColumnInformation.TableIsNullable)) { fm.SetIsNullable(dbfm.IsNullable); } if (HasCapability(ColumnInformation.TableIsPrimaryKey)) { fm.SetIsPrimaryKey(dbfm.IsPrimaryKey); } if (HasCapability(ColumnInformation.TableIsAutoGenerated)) { fm.SetIsAutoGenerated(dbfm.IsAutoGenerated); } if (HasCapability(ColumnInformation.TableIsForeignKey) && dbfm.IsForeignKey) { fm.SetForeignKeyTableName(dbfm.ForeignKeyTableName); fm.SetForeignKeyColumnName(dbfm.ForeignKeyColumnName); } } // remember which fields have been processed (for error reporting later) processedFields.Add(fm); } } catch { // ignore the error but log a warning Check.LogWarning(LogCategories.Metadata, "Type {0} contains no mapping for column {1} in table {2}.", map.Type.Name, dbfm.ColumnName, map.TableName); } } // verify that all defined fields had an existing column in the target table if (isUseData && processedFields.Count < map.Fields.Count) { // construct informative error message StringBuilder sb = new StringBuilder(); bool single = processedFields.Count == map.Fields.Count - 1; sb.AppendFormat("The column{0} ", single ? "" : "s"); bool delimit = false; foreach (FieldMap fm in map.Fields) { if (!processedFields.Contains(fm)) { sb.AppendFormat("{0}{1}", delimit ? ", " : "", fm.ColumnName); delimit = true; } } sb.AppendFormat(" in table {0} do{1} not exist.", map.TableName, single ? "es" : ""); // raise an exception Check.Fail(Error.DeveloperError, sb.ToString()); } } }
private void GetColumnData( TableMap map ) { string sql = String.Format( selectColumns, map.TableName ); SqlStatement stmt = broker.GetStatement( sql ); stmt.StatementType = StatementType.Select; SqlResult sr = stmt.Execute(); for( int i = 0; i < sr.Rows.Count; i++ ) { // returns columns: Field, Type, Null, Key, Default, Extra string columnName = sr.GetString( i, "Field" ); FieldMap fm = map.GetFieldMapFromColumn( columnName ); if( fm == null ) { fm = new FieldMap( map, columnName ); map.Fields.Add( fm ); } if( fm != null ) { string typeinfo = sr.GetString( i, "Type" ); bool isUnsigned; fm.SetDbType( ExtractType( typeinfo, out isUnsigned ), isUnsigned ); if( fm.DbType == (long) MySqlDbType.Enum ) { fm.HandleEnumAsString = true; } fm.SetSize( ExtractSize( typeinfo ) ); fm.SetIsNullable( sr.GetString( i, "Null" ).Equals( "YES" ) ); fm.SetIsPrimaryKey( sr.GetString( i, "Key" ).Equals( "PRI" ) ); if( fm.IsPrimaryKey ) { fm.SetIsAutoGenerated( sr.GetString( i, "Extra" ).Equals( "auto_increment" ) ); } } else // raise an error if we've detected a database/type mismatch { bool hasDefault = sr.GetObject( i, "Default" ) != null; // TODO disabled due to code restructuring // Check.Verify( isNullable || hasDefault, Error.NoPropertyForNotNullColumn, column, map.Type ); } } }
private void GetConstraintData( TableMap map ) { SqlStatement stmt = broker.GetStatement( String.Format( selectConstraints, map.TableName ) ); stmt.StatementType = StatementType.Select; SqlResult sr = stmt.Execute(); if( sr.Rows.Count == 1 ) { // returns columns: Name, Type, Row_format, Rows, Avg_row_length, Data_length, Max_data_length, // Index_length, Data_free, Auto_increment, Create_time, Update_time, Check_time, Create_options, // Comment (as "InnoDB free: 3072 kB; (ListId) REFER test/List(ListId)" string comment = sr.GetString( 0, 1 ); // column 1 is either "Create table" or "Create view" if( comment != null && comment.Length > 5 ) { string[] comments = comment.Split( ',' ); foreach( string cmt in comments ) { string tmp = cmt.Trim(); // samples: // "(Column) REFER database/Table(Column)" // "(`Column`) REFER `database/Table`(`Column`)" string pattern = @"\(`?(?<column>\w+)`?\) REFER .*/(?<fkTable>\w+)[`\s]+\(`?(?<fkColumn>\w+)`?\)"; Regex regex = new Regex( pattern, RegexOptions.ExplicitCapture | RegexOptions.Compiled ); Match m = regex.Match( tmp ); if( m.Success ) { FieldMap fm = map.GetFieldMapFromColumn( m.Groups[ "column" ].Value ); if( fm != null ) { fm.SetForeignKeyTableName( m.Groups[ "fkTable" ].Value ); fm.SetForeignKeyColumnName( m.Groups[ "fkColumn" ].Value ); } } else { //CONSTRAINT `fk_employee_type_employee` FOREIGN KEY (`employee_type_id`) REFERENCES `employee_type` (`employee_type_id`) ON DELETE CASCADE ON UPDATE CASCADE pattern = @"[\s\w]FOREIGN KEY\s\(`?(?<column>\w+)`?\) REFERENCES `?(?<fkTable>\w+)`? \(`?(?<fkColumn>\w+)`?\)[\s\w]+"; Regex regexNew = new Regex( pattern, RegexOptions.ExplicitCapture | RegexOptions.Compiled ); Match mNew = regexNew.Match( tmp ); if( mNew.Success ) { // string constraintPart = mNew.Groups["constraint"].Value; FieldMap fm = map.GetFieldMapFromColumn( mNew.Groups[ "column" ].Value ); if( fm != null ) { fm.SetForeignKeyTableName( mNew.Groups[ "fkTable" ].Value ); fm.SetForeignKeyColumnName( mNew.Groups[ "fkColumn" ].Value ); } } else if( tmp != null ) { int index = tmp.IndexOf( "REFER" ); if( index > 0 ) { string columnName = ExtractColumn( tmp.Substring( 0, index - 1 ) ); tmp = tmp.Substring( index + 5, tmp.Length - index - 5 ).Trim(); index = tmp.IndexOf( "/" ); int start = tmp.IndexOf( "(" ); int end = tmp.IndexOf( ")" ); if( index > 0 && start > 0 && end > start ) { string foreignTable = tmp.Substring( index + 1, start - index - 1 ); string foreignColumn = tmp.Substring( start + 1, end - start - 1 ); FieldMap fm = map.GetFieldMapFromColumn( columnName ); fm.SetForeignKeyTableName( foreignTable ); fm.SetForeignKeyColumnName( foreignColumn ); } } } } } } } }
private void GetColumnData( TableMap map ) { string sql = String.Format( selectColumns, map.TableName ); SqlStatement stmt = broker.GetStatement( sql ); stmt.StatementType = StatementType.Select; SqlResult sr = stmt.Execute(); for( int i = 0; i < sr.Rows.Count; i++ ) { // returns columns: Field, Type, TypeSize, FieldSize, NotNull, HasDefault, Default string columnName = sr.GetString( i, "field" ); // get or create FieldMap for column FieldMap fm = map.GetFieldMapFromColumn( columnName ); if( fm == null ) { fm = new FieldMap( map, columnName ); map.Fields.Add( fm ); } bool isNullable = sr.GetString( i, "notnull" ).Trim().ToLower().StartsWith( "f" ); if( fm != null ) { bool hasDefault = sr.GetBoolean( i, "hasdefault" ); fm.SetDbType( sr.GetString( i, "type" ), false ); int size = ExtractSize( sr.GetInt( i, "typesize" ), sr.GetInt( i, "fieldsize" ) ); fm.SetSize( size ); fm.SetIsNullable( isNullable ); //fm.SetIsPrimaryKey( sr.GetString( i, "Key" ).Equals( "PRI" ) ); // fm.SetIsForeignKey( sr.GetString( i, "Key" ).Equals( "FOR" ) ); //if( fm.IsPrimaryKey ) // fm.SetIsAutoGenerated( sr.GetString( i, "Key" ).Equals( "auto_increment" ) ); //if( sr.GetString( i, "HasDefault" ).Equals( "t" ) ) // fm.SetMagicValue( sr.GetObject( i, "Default" ) ); } } }
private void UpdateTableMapWithColumnInformation( TableMap map ) { SqlResult sr = broker.Execute( String.Format( selectColumns, map.TableName ), null, null ); // process result set using columns: cid, name, type, notnull, dflt_value, pk for( int i=0; i<sr.RowsContained; i++ ) { string columnName = sr.GetString( i, "name" ); FieldMap fm = map.GetFieldMapFromColumn( columnName ); if( fm == null ) { fm = new FieldMap( map, columnName ); map.Fields.Add( fm ); } // get basic column information fm.SetDbType( sr.GetString( i, "type" ), false ); fm.SetIsNullable( ! sr.GetBoolean( i, "notnull" ) ); fm.SetIsPrimaryKey( sr.GetBoolean( i, "pk" ) ); fm.SetIsAutoGenerated( fm.IsPrimaryKey && (fm.Type == typeof(int) || fm.Type == typeof(long)) ); } }
/// <summary> /// Constructor for fields using information obtained directly from the database (no property info). /// </summary> public FieldMap(TableMap map, string columnName) { this.map = map; SetColumnName(columnName); }
private void UpdateTableMapWithIndexInformation( TableMap map ) { SqlResult sr = broker.Execute( String.Format( selectIndexes, map.TableName ), null, null ); // process result set using columns: name, unique for( int i=0; i<sr.RowsContained; i++ ) { string indexName = sr.GetString( i, "name" ); SqlResult indexInfo = broker.Execute( String.Format( selectIndex, map.TableName ), null, null ); // process result set using columns: seqno, cid, name for( int indexColumn=0; indexColumn<sr.RowsContained; indexColumn++ ) { // fm.SetIsAutoGenerated( sr.GetString( i, "dflt_value" ).Length > 0 ? true : false ); } } }
/// <summary> /// Constructor for fields using information obtained from the TableColumn attribute. /// </summary> public FieldMap(ObjectMap map, MemberAttributeInfo memberAttributeInfo) { this.map = map; memberInfo = memberAttributeInfo.MemberInfo; if (memberInfo is PropertyInfo) { memberType = (memberInfo as PropertyInfo).PropertyType; } else { memberType = (memberInfo as FieldInfo).FieldType; } // extract information from attributes if (memberAttributeInfo.Attributes != null) { foreach (Attribute attr in memberAttributeInfo.Attributes) { if (attr is TableColumnAttribute) { TableColumnAttribute tc = attr as TableColumnAttribute; SetColumnName(tc.Name ?? memberInfo.Name); SetNullValue(tc.NullValue); SetIsNullable(!tc.NotNull); SetSize(tc.Size); if (tc.HasDbType) { SetDbType(tc.DatabaseType); } else { SetDbType(NO_DBTYPE); } handleEnumAsString = tc.HandleEnumAsString; isReadOnly = tc.IsReadOnly; isUpdateAfterWrite = tc.IsUpdateAfterWrite; } else if (attr is PrimaryKeyAttribute) { PrimaryKeyAttribute pk = attr as PrimaryKeyAttribute; SetIsPrimaryKey(true); SetIsAutoGenerated(pk.AutoGenerated); if (IsAutoGenerated) { map.IdentityMap = this; } } else if (attr is ForeignKeyAttribute) { ForeignKeyAttribute fk = attr as ForeignKeyAttribute; SetForeignKeyTableName(fk.ForeignTable); SetForeignKeyColumnName(fk.ForeignColumn); } else if (attr is ConcurrencyAttribute) { ConcurrencyAttribute ca = attr as ConcurrencyAttribute; Check.Verify(memberType == typeof(int) || memberType == typeof(long), Error.DeveloperError, "Unsupported property type {0} for ConcurrencyAttribute {1}", memberInfo.ReflectedType, memberInfo.Name); isConcurrencyColumn = true; map.ConcurrencyMap = this; } else if (attr is SoftDeleteAttribute) { SoftDeleteAttribute sd = attr as SoftDeleteAttribute; Check.Verify(memberType == typeof(int) || memberType == typeof(long), Error.DeveloperError, "Unsupported property type {0} for SoftDeleteAttribute {1}", memberInfo.ReflectedType, memberInfo.Name); isSoftDeleteColumn = true; map.SoftDeleteMap = this; } else if (attr is SequenceNameAttribute) { // sequence name used when available (in place of name conventions or autodetected value) sequenceName = (attr as SequenceNameAttribute).Name; } else if (attr is InheritanceAttribute) { // sequence name used when available (in place of name conventions or autodetected value) map.InheritanceMap = this; } } } }
public override void Analyze( string tableName ) { try { bool isSingleRun = tableName != null; DataTable dt = GetTables( tableName ); foreach( DataRow row in dt.Rows ) { try { string dbTableName = (string) row[ "TABLE_NAME" ]; // skip Access system tables if( ! dbTableName.StartsWith( "MSysAccess" ) ) { if( ! isSingleRun || tableName.ToLower().Equals( dbTableName.ToLower() ) ) { TableMap map = GetTableMap( dbTableName ); if( map == null ) { map = new TableMap( provider, dbTableName ); maps[ dbTableName.ToLower() ] = map; } // get column information for this table GetColumnData( map ); // abort loop if analyzing single table only if( isSingleRun ) { break; } } } } catch( GentleException fe ) { // ignore errors caused by tables found in db but for which no map exists // TODO this should be a config option if( fe.Error != Error.NoObjectMapForTable ) { throw fe; } } } // get information on primary and foreign keys (for tables found here) GetPrimaryKeyData(); GetForeignKeyData(); } catch( Exception e ) { Check.Fail( e, Error.Unspecified, "An error occurred while analyzing the database schema." ); } }
/// <summary> /// Constructor for fields using information obtained directly from the database (no property info). /// </summary> public FieldMap( TableMap map, string columnName ) { this.map = map; SetColumnName( columnName ); }