/// <summary> /// Builds and returns a new record using the schema and values stored in this builder. /// </summary> /// <param name="autoDispose">True to dispose this builder as soon as the new record is generated.</param> /// <returns>A new record built using the schema and values stored in this builder.</returns> public KRecord Generate( bool autoDispose = true ) { if( _Schema == null ) throw new InvalidOperationException( "Builder Schema is null." ); if( _Schema.Count < 0 ) throw new InvalidOperationException( "Builder Schema is disposed." ); if( _Schema.Count == 0 ) throw new InvalidOperationException( "Builder Schema is empty." ); KRecord record = new KRecord( _Schema ); for( int i = 0; i < _Values.Count; i++ ) record[i] = _Values[i]; if( autoDispose ) Dispose(); return record; }
protected virtual void Dispose( bool disposing ) { _Record = null; _Table = null; }
internal KRecordDynamicTable( KRecord record, string table ) { _Record = record; _Table = table.Validated( "Table Name" ); }
/// <summary> /// Returns whether this record can be considered equivalent to the other record. /// <para>Strict mode can be requested, 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>Whether this record can be considered equivalent to the other record.</returns> public bool EquivalentTo( KRecord other, bool strict = true ) { KRecord changes = Changes( other, strict ); bool r = changes == null ? true : false; if( changes != null ) { changes.Schema.Dispose(); changes.Dispose(); } return r; }
/// <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; }
/// <summary> /// Returns a new clone of this record, optionally cloning the schema it was associated to. /// <para>If cloning the schema was not requested, then the new clone will be associated whith the original schema /// instance. Otherwise, it will be associated with a clone of the original schema.</para> /// <para>It also tries to clone the contents of the original record, if possible.</para> /// </summary> /// <param name="cloneSchema">True to also clone the schema.</param> /// <returns>The newly created clone.</returns> public KRecord Clone( bool cloneSchema ) { KRecord cloned = new KRecord(); if( _Schema == null ) throw new InvalidOperationException( "Cannot clone from a record with a null schema." ); if( _Schema.Count == 0 ) throw new InvalidOperationException( "Cannot clone from a record with an empty schema." ); cloned._Columns = new object[_Schema.Count]; for( int i = 0; i < _Columns.Length; i++ ) cloned._Columns[i] = TypeHelper.TryClone( _Columns[i] ); cloned._Schema = cloneSchema ? _Schema.Clone() : _Schema; cloned._Sealed = _Sealed; cloned._SerializeSchema = _SerializeSchema; return cloned; }