protected virtual void Dispose( bool disposing ) { DEBUG.IndentLine( "\n-- KRecordBuilder.Dispose( Disposing={0} ) - This={1}", disposing, this ); if( _Values != null ) { _Values.Clear(); _Values = null; } _Schema = null; // It might be in use elsewhere DEBUG.Unindent(); }
private KRecord() { } // For the specialized Clone() and Changes() methods... /// <summary> /// Creates a new <see cref="KRecord"/> instance using the given schema to define its columns. /// <para>The schema will be sealed in order to avoid changes to it (because the structure of the record is created /// in this constructor, but the record does not keep track of any future changes in the schema).</para> /// </summary> /// <param name="schema">The schema defining the columns in this record.</param> public KRecord( KSchema schema ) { DEBUG.IndentLine( "\n-- KRecord( Schema={0} )", schema == null ? "null" : schema.ToString() ); if( ( _Schema = schema ) == null ) throw new ArgumentNullException( "schema", "Schema cannot be null." ); if( _Schema.Count <= 0 ) throw new ArgumentException( "Invalid number of columns in schema: " + _Schema ); _Schema.Sealed = true; _Columns = new object[_Schema.Count]; DEBUG.Unindent(); }
protected virtual void Dispose( bool disposing ) { DEBUG.IndentLine( "\n-- KRecord.Dispose( Disposing={0} ) - This={1}", disposing, this ); if( _Columns != null ) { for( int i = 0; i < _Columns.Length; i++ ) _Columns[i] = null; _Columns = null; } _Schema = null; // Might be in use elsewhere DEBUG.Unindent(); }
protected override void Dispose( bool disposing ) { DEBUG.IndentLine( "\n-- KEnumeratorWCF.Dispose( Disposing={0} ) - This={1}", disposing, this ); if( _EnumeratorId != Guid.Empty ) { if( Link != null && Link.Proxy != null ) Link.Proxy.EnumeratorDispose( _EnumeratorId ); _EnumeratorId = Guid.Empty; } _Schema = null; base.Dispose( disposing ); // Calls-back Reset() - but with no effects... DEBUG.Unindent(); }
/// <summary> /// Advances this enumerator to return the next element from the database. /// <para>In this implementation these elements are not maintained in an in-memory structure, but rather are retrieved /// and maintained in the CurrentRecord property just until the next invocation of MoveNext(). /// </summary> /// <returns>True if the next element has been obtained, false if there are no more elements available.</returns> public override bool MoveNext() { // First iteration... if( _Surrogate == null ) { _Surrogate = new KSurrogate( this.Command, iterable: true ); _Schema = _Surrogate._Schema; } // If we have finished, cleaning it up... if( !_Surrogate._DataReader.Read() ) { DEBUG.IndentLine( "\n-- MoveNext: null" ); DEBUG.Unindent(); _Surrogate.Dispose(); _Surrogate = null; return false; } // Else, generating the record... _CurrentRecord = new KRecord( _Schema ); for( int i = 0; i < _Schema.Count; i++ ) { object value = _Surrogate._DataReader.IsDBNull( i ) ? null : _Surrogate._DataReader.GetValue( i ); _CurrentRecord[i] = value; } DEBUG.IndentLine( "\n-- MoveNext: {0}", CurrentRecord.ToString() ); DEBUG.Unindent(); return true; }
/// <summary> /// Resets this enumerator. /// </summary> public override void Reset() { if( _EnumeratorId != Guid.Empty ) { if( Link != null && Link.Proxy != null ) Link.Proxy.EnumeratorReset( _EnumeratorId ); _EnumeratorId = Guid.Empty; } _Schema = null; // Do not dispose, might be in use elsewhere... }
/// <summary> /// Returns a new ad-hoc record containing the changes from this record compared against the other record given. /// <para>Strict mode can be requeste, in which case all columns in both records are taken in consideration.</para> /// <para>When not in strict mode, only the columns of the source record are compared.</para> /// </summary> /// <param name="other">The other record to use in the comparison.</param> /// <param name="strict">True to activate strict mode, false otherwise.</param> /// <returns>A new record containing the changes and its schema, or null if no changes were detected.</returns> public KRecord Changes( KRecord other, bool strict = false ) { if( this._Schema == null ) throw new InvalidOperationException( "This record's schema is null." ); if( this.Schema.Count < 0 ) throw new InvalidOperationException( "This record's schema is disposed." ); if( other == null ) throw new ArgumentNullException( "other", "Other record cannot be null." ); if( other.Schema == null ) throw new InvalidOperationException( "Other record's schema is null." ); if( other.Schema.Count < 0 ) throw new InvalidOperationException( "Other record's schema is disposed." ); // If any record is empty... if( this.Schema.Count == 0 ) { if( other.Schema.Count == 0 ) return null; // Both are empty records... if( !strict ) return null; // We have no changes to inform about... return other.Clone( cloneSchema: true ); // All other contents are consideres as changed... } if( other.Schema.Count == 0 ) { if( !strict ) return null; // We have no changes to inform about... return this.Clone( cloneSchema: true ); // All other contents are consideres as changed... } // Preparing for returning a new record containing the changes... KSchema schema = new KSchema( _Schema.CaseSensitiveNames ); List<object> values = new List<object>(); bool anyTable = strict ? false : true; // First round: using this record's columns... for( int thisIx = 0; thisIx < this.Schema.Count; thisIx++ ) { var thisMeta = this.Schema[thisIx]; var otherMeta = other.Schema.Find( thisMeta.BaseTableName, thisMeta.ColumnName, anyTable, raise: false ); if( otherMeta == null ) { // Columns not found in other are considered only in strict mode... if( strict ) { object thisValue = this[thisIx]; schema.Add( thisMeta.Clone() ); values.Add( TypeHelper.TryClone( thisValue ) ); } } else { // Only annotating when their contents are not equivalent... int otherIx = other.Schema.IndexOf( otherMeta ); object thisValue = this[thisIx]; object otherValue = other[otherIx]; bool eq = TypeHelper.AreEquivalent( thisValue, otherValue ); if( !eq ) { schema.Add( thisMeta.Clone() ); values.Add( TypeHelper.TryClone( thisValue ) ); } } } // Second round: in strict we need to consider also the columns in other that do not appear in this... if( strict ) { for( int otherIx = 0; otherIx < other.Schema.Count; otherIx++ ) { var otherMeta = other.Schema[otherIx]; var thisMeta = this.Schema.Find( otherMeta.BaseTableName, otherMeta.ColumnName, anyTable: false, raise: false ); if( thisMeta == null ) { // Adding from a new column in the other record... var temp = schema.Find( otherMeta.BaseTableName, otherMeta.ColumnName, anyTable: true, raise: false ); if( temp == null ) { // Avoiding exception per duplicate columns... object otherValue = other[otherIx]; schema.Add( otherMeta.Clone() ); values.Add( TypeHelper.TryClone( otherValue ) ); } } } } // If no changes return null to facilitate comparisons... if( schema.Count == 0 ) { values = null; schema.Dispose(); schema = null; return null; } // Otherwise, generating the actual record containing the changes... KRecord record = new KRecord(); record._Schema = schema; record._Columns = values.ToArray(); return record; }
protected KRecord( SerializationInfo info, StreamingContext context ) { int count = (int)info.GetValue( "ColumnCount", typeof( int ) ); _Columns = new object[count]; for( int i = 0; i < count; i++ ) { string type = info.GetString( "ColumnType" + i ); object value = type == "VOID" ? null : info.GetValue( "ColumnValue" + i, Type.GetType( type ) ); _Columns[i] = value; } _Sealed = info.GetBoolean( "RecordSealed" ); _SerializeSchema = info.GetBoolean( "SerializeSchema" ); if( _SerializeSchema ) _Schema = (KSchema)info.GetValue( "Schema", typeof( KSchema ) ); }
/// <summary> /// Resets this enumerator. /// </summary> public override void Reset() { if( _Surrogate != null ) { _Surrogate.Dispose(); _Surrogate = null; } _Schema = null; _CurrentRecord = null; }
void Invoke( bool iterable ) { // Opening if needed... if( !_Link.IsDbOpened ) { _Link.DbOpen(); _LinkOpenedBySurrogate = true; } // Creating the database command and its parameters... IDbCommand cmd = _Link.DbConnection.CreateCommand(); cmd.CommandText = _Command.CommandText( iterable ); string nullStr = _Command.Parser.Parse( null, nulls: true ); // To substitute parameters with NULL values... foreach( var par in _Command.Parameters ) { if( par.Value == null ) cmd.CommandText = cmd.CommandText.Replace( par.Name, nullStr ); else { IDataParameter dbpar = cmd.CreateParameter(); dbpar.ParameterName = par.Name; dbpar.Value = _Link.TransformParameterValue( par.Value ); cmd.Parameters.Add( dbpar ); } } // Setting the transaction... Transaction scope = Transaction.Current; if( scope != null ) { } // Managed by TransactionScope else { IDbTransaction tx = null; // Using the current connection's transaction, if exists... var innerConnection = TypeHelper.GetElementValue( _Link.DbConnection, "InnerConnection" ); if( innerConnection != null ) { var currentTransaction = TypeHelper.GetElementValue( innerConnection, "CurrentTransaction" ); if( currentTransaction != null ) { var parent = TypeHelper.GetElementValue( currentTransaction, "Parent" ); if( parent != null ) tx = (IDbTransaction)parent; } } if( tx != null ) cmd.Transaction = tx; } // Execute if NON-QUERY... if( !iterable ) { try { _NonQueryResult = cmd.ExecuteNonQuery(); } catch { throw; } finally { cmd.Dispose(); cmd = null; } return; } // OTHERWISE, we need to capture the datareader and the schema returned from the database... try { _DataReader = cmd.ExecuteReader( CommandBehavior.KeyInfo ); } catch { throw; } finally { cmd.Dispose(); cmd = null; } // Creating the schema... DataTable table = _DataReader.GetSchemaTable(); if( table == null ) throw new InvalidOperationException( "Cannot obtain schema table for command: " + cmd ); string tablename = _Command is IKTableNameProvider ? ( (IKTableNameProvider)_Command ).TableName : null; _Schema = new KSchema( _Link.DbCaseSensitiveNames ); for( int i = 0; i < table.Rows.Count; i++ ) { DataRow row = table.Rows[i]; string meta = null; object value = null; bool hidden = false; if( table.Columns.Contains( "IsHidden" ) ) { value = row[table.Columns["IsHidden"]]; if( !( value is DBNull ) ) hidden = (bool)value; } if( hidden ) continue; KMetaColumn column = new KMetaColumn(); for( int j = 0; j < table.Columns.Count; j++ ) { meta = table.Columns[j].ColumnName; value = row[j] is DBNull ? null : row[j]; if( value != null ) column[meta] = value; } if( column.BaseTableName == null && tablename != null ) column.BaseTableName = tablename; DEBUG.WriteLine( "-- Schema Column: {0}", column ); _Schema.Add( column ); } table.Dispose(); table = null; // Setting the aliases if needed... if( _Command is IKTableAliasListProvider ) _Schema.TableAliasList.AddRange( ( (IKTableAliasListProvider)_Command ).TableAliasList ); // And finishing with the schema... _Schema.Sealed = true; }
protected virtual void Dispose( bool disposing ) { DEBUG.IndentLine( "\n-- KSurrogate.Dispose( Disposing={0} ) - This={1}", disposing, this ); if( _DataReader != null ) { if( !_DataReader.IsClosed ) _DataReader.Close(); _DataReader.Dispose(); _DataReader = null; } if( _Link != null ) { if( _LinkOpenedBySurrogate ) _Link.DbClose(); _Link = null; } _Schema = null; // It might be in use elsewhere _Command = null; DEBUG.Unindent(); }
/// <summary> /// Creates a new instance of <see cref="KRecordBuilder"/>. /// <para>Its TableAliasList property can be used to add the aliases needed for the schema.</para> /// </summary> /// <param name="caseSensitiveNames">Whether the names of tables and columns are considered case sensitively or /// not.</param> public KRecordBuilder( bool caseSensitiveNames ) { DEBUG.IndentLine( "\n-- KRecordBuilder( CaseSensitive={0} )", caseSensitiveNames ); _Schema = new KSchema( caseSensitiveNames ); DEBUG.Unindent(); }