/*=========================*/
        #endregion

        #region Internal Methods
        /*=========================*/

        /// <summary>
        /// Fills the item with data retrieved from the data source using the select command.
        /// </summary>
        protected void Bind()
        {
            // Cannot bind when the table is not managed inside the item
            if (_owner != null)
            {
                throw new InvalidOperationException("Cannot independently bind an item that is part of a collection");
            }

            if (DataManager.ProxyMode)
            {
                ProxyRequestAction action = ProxyClient.Request.AddAction(this, MethodInfo.GetCurrentMethod());
                action.OnComplete = delegate()
                {
                    DataTable table = ProxyClient.Result[action].GetData <DataTable>("_table");
                    _table = table;
                    _row   = table.Rows[0];

                    // TODO: deal with any field backups and shit
                };
            }
            else
            {
                // Initialize the table
                if (_table == null)
                {
                    _table = new DataTable("_table");
                }
                else
                {
                    _table.Rows.Clear();
                }

                SqlDataAdapter adapter = DataManager.CreateAdapter(this);

                ConnectionKey ckey = null;
                try
                {
                    ckey = DataManager.Current.OpenConnection(this);

                    // Fill the table
                    adapter.Fill(this._table);
                }
                finally
                {
                    DataManager.Current.CloseConnection(ckey);
                }

                if (_table.Rows.Count < 1)
                {
                    throw new DataException("Binding operation did not return data");
                }

                _row = _table.Rows[0];

                if (ProxyServer.InProgress)
                {
                    ProxyServer.Current.Result[ProxyServer.Current.CurrentAction].AddData("_table", _table);
                }
            }
        }
        /// <summary>
        /// Invoked when the item needs to be deleted from the data source in independent mode.
        /// </summary>
        ///
        /// <remarks>
        /// <para>
        /// The base implementation of this method uses a DataAdapter with the item's DeleteCommand
        /// in order to delete the record from the database. After deleting, the item
        /// and it's fields remain fully accessible from memory only and so can be resaved.
        /// </para>
        /// <para>
        /// Derived classes can override this method to add additional
        /// checks or operations before and after the delete, or to change the delete process altogether.
        /// </para>
        /// </remarks>
        protected virtual void OnDelete()
        {
            // Cannot update when the table is not managed inside the item
            if (_owner != null)
            {
                throw new InvalidOperationException("Cannot independently delete an item that is part of a collection." +
                                                    " Use the Remove or RemoveAt methods to delete the item from the collection and then use Save to save the data to the database.");
            }

            if (this.DataState == DataRowState.Deleted ||
                this.DataState == DataRowState.Detached
                )
            {
                throw new InvalidOperationException("Cannot delete an item with the DataState of " + this.DataState.ToString());
            }

            if (DataManager.ProxyMode)
            {
                ProxyClient.Request.AddAction(this, MethodInfo.GetCurrentMethod()).OnComplete = delegate()
                {
                    _row.SetAdded();
                };
            }
            else
            {
                // Preserve the items so we can re-insert them (deleting clears the row)
                object[] dataBeforeDelete = new object[_row.ItemArray.Length];
                _row.ItemArray.CopyTo(dataBeforeDelete, 0);

                // Delete the row
                _row.Delete();

                // Create an adapter
                SqlDataAdapter adapter = DataManager.CreateAdapter(this);

                ConnectionKey ckey = null;
                using (adapter)
                {
                    try
                    {
                        ckey = DataManager.Current.OpenConnection(this);

                        adapter.Update(_table);
                    }
                    finally
                    {
                        DataManager.Current.CloseConnection(ckey);
                    }
                }

                // Re-add the row so it can be accessed again (only when not part of a collection)
                if (_owner == null)
                {
                    _table.Rows.Add(_row);
                    _row.ItemArray = dataBeforeDelete;
                }
            }
        }
예제 #3
0
        /*=========================*/
        #endregion

        #region Internal Methods
        /*=========================*/

        /// <summary>
        /// Populates the collection with DataItem objects by binding to the data source.
        /// </summary>
        ///
        /// <remarks>
        /// Calling this method clears the inner table before re-populating the list, which means
        /// items contained in the collection before the binding call are disassociated from the collection
        /// (their <c>DataState</c> changes to <c>DataRowState.Detached</c>). Changes to detached items
        /// will not be saved when the collection is saved (unless they are re-added).
        /// </remarks>
        protected void Bind()
        {
            // Clear the table
            _table.Rows.Clear();

            // Clear items
            _innerList.Clear();
            if (_hash != null)
            {
                _hash.Clear();
            }

            if (!DataManager.ProxyMode)
            {
                // Attach an event handler to the table so we can create DataItems for each row added
                DataRowChangeEventHandler addedHandler = new DataRowChangeEventHandler(_table_RowChanged);
                _table.RowChanged += addedHandler;

                SqlDataAdapter adapter = DataManager.CreateAdapter(this);
                ConnectionKey  ckey    = null;
                try
                {
                    ckey = DataManager.Current.OpenConnection(this);

                    // Fill the table
                    adapter.Fill(this._table);
                }
                finally
                {
                    DataManager.Current.CloseConnection(ckey);
                }

                // Detach the event so it doesn't get raised in future changes
                _table.RowChanged -= addedHandler;

                if (ProxyServer.InProgress)
                {
                    ProxyServer.Current.Result[ProxyServer.Current.CurrentAction].AddData("_table", _table);
                }
            }
            else
            {
                ProxyRequestAction action = ProxyClient.Request.AddAction(this, MethodInfo.GetCurrentMethod());
                action.OnComplete = delegate()
                {
                    DataTable table = ProxyClient.Result[action].GetData <DataTable>("_table");
                    _table = table;

                    // Create new items for each row using the existing handler
                    foreach (DataRow row in _table.Rows)
                    {
                        _table_RowChanged(_table, new DataRowChangeEventArgs(row, DataRowAction.Add));
                    }
                };
            }
        }
        /// <summary>
        /// Invoked when the item needs to be saved to the data source in independent mode.
        /// </summary>
        ///
        /// <remarks>
        /// The base implementation of this method uses a DataAdapter with the item's UpdateCommand
        /// in order to save it's fields to the database. Derived classes can override this method to add additional
        /// checks or operations before and after the save, or to change the saving method altogether.
        /// </remarks>
        protected virtual void OnSave()
        {
            // Cannot update when the table is not managed inside the item
            if (_owner != null)
            {
                throw new InvalidOperationException("Cannot independently save an item that is part of a collection");
            }

            // Rather than just allowing the adapter to skip the row, throw and exception to notify the consumer
            if (this.DataState != DataRowState.Added &&
                this.DataState != DataRowState.Modified &&
                this.DataState != DataRowState.Unchanged
                )
            {
                throw new InvalidOperationException("Cannot save an item with the DataState of " + this.DataState.ToString());
            }

            if (DataManager.ProxyMode)
            {
                ProxyRequestAction action = ProxyClient.Request.AddAction(this, MethodInfo.GetCurrentMethod());
                action.OnComplete = delegate()
                {
                    DataTable table = ProxyClient.Result[action].GetData <DataTable>("_table");
                    _table = table;
                    _row   = table.Rows[0];

                    // TODO: deal with any field backups and shit
                };
            }
            else
            {
                // Create an adapter
                SqlDataAdapter adapter = DataManager.CreateAdapter(this);

                ConnectionKey ckey = null;
                using (adapter)
                {
                    try
                    {
                        ckey = DataManager.Current.OpenConnection(this);
                        adapter.Update(_table);
                    }
                    finally
                    {
                        DataManager.Current.CloseConnection(ckey);
                    }
                }

                if (ProxyServer.InProgress)
                {
                    ProxyServer.Current.Result[ProxyServer.Current.CurrentAction].AddData("_table", _table);
                }
            }
        }
예제 #5
0
        /// <summary>
        /// Ignores any keys and forces the connection to close.
        /// </summary>
        public void ForceCloseConnection()
        {
            _connectionKey = null;

            if (_connection != null && _connection.State == ConnectionState.Open)
            {
                if (_transaction != null)
                {
                    CommitTransaction();
                }

                _connection.Close();
            }

            _transaction = null;
            _connection  = null;
        }
예제 #6
0
        /// <summary>
        /// Manages connection open based on sequence.
        /// </summary>
        ///
        /// <param name="dataObj">If not null, associates the connection with the object's data commands.</param>
        ///
        /// <returns>
        ///	When opening a new connection, an object that can be used to close the connection.
        ///	Null if the connection is already open.
        ///	</returns>
        public ConnectionKey OpenConnection(IDataBoundObject dataObj, SqlConnection externalConnection)
        {
            //Check for a valid connection string
            if (externalConnection == null && (_connectionString == "" || _connectionString == null))
            {
                return(null);
            }

            // This is the key used to close the connection.
            ConnectionKey key = null;

            // If a connection doesn't exist, open a new one
            // (second condition is just in case, should never happen because we nullify the connection when closing it)
            if (_connection == null || _connection.State == ConnectionState.Closed)
            {
                if (externalConnection != null)
                {
                    _connection = externalConnection;
                }
                else
                {
                    _connection = new SqlConnection(_connectionString);
                    key         = new ConnectionKey();
                }
            }

            // Associate the data bound object's commands with the current connection
            if (dataObj != null)
            {
                SetActiveConnection(dataObj);
            }

            if (key != null)
            {
                _connectionKey = key;
                _connection.Open();
            }

            return(key);
        }
예제 #7
0
        /// <summary>
        /// Deletes the rows in the table, updates the database and then re-adds the rows.
        /// </summary>
        /// <remarks>
        /// Used to disassociate a collection from a parent object but allowing the values to be reused.
        /// (used in <see cref="PT.Data.QueryKeywordGroupCollection"/>).
        /// </remarks>
        protected void DeleteFromDB()
        {
            if (DataManager.ProxyMode)
            {
                throw new NotSupportedException("DeleteFromDB currently not supported in proxy mode");
            }

            // Delete all rows
            foreach (DataRow row in _table.Rows)
            {
                row.Delete();
            }

            // Update to DB
            SqlDataAdapter adapter = DataManager.CreateAdapter(this);

            ConnectionKey ckey = null;

            using (adapter)
            {
                try
                {
                    ckey = DataManager.Current.OpenConnection(this);

                    adapter.Update(_table);
                }
                finally
                {
                    DataManager.Current.CloseConnection(ckey);
                }
            }

            // Restore all item rows that are still in the list (not items that were removed
            foreach (DataItem item in this._innerList)
            {
                _table.Rows.Add(item.Row);
                item.RestoreFieldValues();
            }
        }
예제 #8
0
        /// <summary>
        /// Closes the open connection if <pararef name="key">key</pararef> matches the active key.
        /// </summary>
        ///
        /// <param name="key">
        /// The key returned by <see cref="OpenConnection"/>. If key is null or does not match the
        /// current valid key, the method does not do anything.
        /// </param>
        ///
        public void CloseConnection(ConnectionKey key)
        {
            if (
                key != null &&
                _connectionKey == key &&
                _connection != null
                )
            {
                if (_connection.State == ConnectionState.Open)
                {
                    if (_transaction != null)
                    {
                        CommitTransaction();
                    }

                    _connection.Close();
                }

                _transaction   = null;
                _connection    = null;
                _connectionKey = null;
            }
        }
        /// <summary>
        /// Manages connection open based on sequence.
        /// </summary>
        ///
        /// <param name="dataObj">If not null, associates the connection with the object's data commands.</param>
        ///
        /// <returns>
        ///	When opening a new connection, an object that can be used to close the connection.
        ///	Null if the connection is already open.
        ///	</returns>
        public ConnectionKey OpenConnection(SqlConnection externalConnection)
        {
            //Check for a valid connection string
            if (externalConnection == null && (_connectionString == "" || _connectionString == null))
            {
                return(null);
            }

            // This is the key used to close the connection.
            ConnectionKey key = null;

            // If a connection doesn't exist, open a new one
            // (second condition is just in case, should never happen because we nullify the connection when closing it)
            if (_connection == null || _connection.State == ConnectionState.Closed)
            {
                if (externalConnection != null)
                {
                    _connection = externalConnection;
                }
                else
                {
                    _connection = new SqlConnection(_connectionString);
                    key         = new ConnectionKey();
                }
            }



            if (key != null)
            {
                _connectionKey = key;
                _connection.Open();
            }

            return(key);
        }
        /// <summary>
        /// Runs the stand-alone SELECT command to retrieve fields that were not present when the item was
        /// created (in either independent or collection-owned mode).
        /// </summary>
        public virtual void RetrieveMissingFields()
        {
            if (DataManager.ProxyMode)
            {
                ProxyRequestAction action = ProxyClient.Request.AddAction(this, MethodInfo.GetCurrentMethod());
                action.OnComplete = delegate()
                {
                    DataTable table = ProxyClient.Result[action].GetData <DataTable>("_table");
                    _table = table;
                    _missingFields.Clear();

                    // When no owner just swap tables,
                    if (_owner == null)
                    {
                        _row = table.Rows[0];
                    }
                    else
                    {
                        _retrievedFieldRow = table.Rows[0];
                    }
                };
            }
            else
            {
                if (SelectCommand == null)
                {
                    throw new InvalidOperationException("There is no defined SELECT command so missing fields cannot be retrieved.");
                }

                // Only do something if there are missing fields to complete
                if (_missingFields.Count > 0 && _selectCmd != null)
                {
                    ConnectionKey key = null;

                    // Gets parameter values
                    foreach (SqlParameter param in SelectCommand.Parameters)
                    {
                        if (param.SourceColumn != null && param.SourceColumn != String.Empty)
                        {
                            // Map to the row or to the backup hash according to state
                            param.Value = _row.RowState == DataRowState.Deleted || _row.RowState == DataRowState.Detached ?
                                          _backupFieldValues[param.SourceColumn] :
                                          _row[param.SourceColumn];
                        }
                        else
                        {
                            param.Value = DBNull.Value;
                        }
                    }

                    try
                    {
                        key = DataManager.Current.OpenConnection(this);
                        SqlDataReader reader = SelectCommand.ExecuteReader();
                        using (reader)
                        {
                            if (!reader.HasRows)
                            {
                                throw new DataItemInconsistencyException("Error retrieving item data - item no longer exists");
                            }
                            else
                            {
                                // Read the first row
                                reader.Read();

                                DataRow rowToUse;

                                // When object is part of the collection, initialize the internal table to hold retrieved fields
                                if (_owner != null && _table == null)
                                {
                                    _table = new DataTable("_table");
                                    OnInitializeTable();
                                    _retrievedFieldRow = _table.NewRow();
                                    _table.Rows.Add(_retrievedFieldRow);

                                    rowToUse = _retrievedFieldRow;
                                }
                                else
                                {
                                    rowToUse = _row;
                                }

                                foreach (string missingField in _missingFields)
                                {
                                    try
                                    {
                                        if ((_row.RowState == DataRowState.Deleted || _row.RowState == DataRowState.Detached) &&
                                            rowToUse == _row)
                                        {
                                            // Update the backup hash when state is inaccessible
                                            _backupFieldValues[missingField] = reader[missingField];
                                        }
                                        else
                                        {
                                            rowToUse[missingField] = reader[missingField];
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        // If a field assigment failed, the select command
                                        throw new DataItemInconsistencyException("Error setting item data - retrieved data does not match item's internal structure", ex);
                                    }
                                }

                                // Done getting the missing fields, so clear them
                                _missingFields.Clear();
                            }
                        }
                    }
                    finally
                    {
                        DataManager.Current.CloseConnection(key);
                    }
                }
                if (ProxyServer.InProgress)
                {
                    ProxyServer.Current.Result[ProxyServer.Current.CurrentAction].AddData("_table", _table);
                }
            }
        }
예제 #11
0
        /// <summary>
        /// Handles saving the collection's items to the data source.
        /// </summary>
        ///
        /// <remarks>
        /// The base implementation of this method uses a DataAdapter with the collection's associated commands
        /// in order to save the contained records to the database. Derived classes can override this method to add additional
        /// checks or operations before and after the save, or to change the saving method altogether.
        /// </remarks>
        protected virtual void OnSave()
        {
            // Don't perform the save if there are no changes
            if (_table.GetChanges() == null)
            {
                return;
            }

            if (!DataManager.ProxyMode)
            {
                // Create an adapter
                SqlDataAdapter adapter = DataManager.CreateAdapter(this);

                // Vars for proxy operations
                DataTable updatedRowsTable = null;
                SqlRowUpdatedEventHandler updatedHander = null;

                if (ProxyServer.InProgress)
                {
                    updatedRowsTable = _table.Clone();
                    updatedHander    = delegate(object sender, SqlRowUpdatedEventArgs e)
                    {
                        if (e.StatementType != StatementType.Insert && e.StatementType != StatementType.Update)
                        {
                            return;
                        }

                        // Store and row that has been inserted or updated
                        updatedRowsTable.ImportRow(e.Row);
                    };

                    adapter.RowUpdated += updatedHander;
                }

                ConnectionKey ckey = null;
                using (adapter)
                {
                    try
                    {
                        ckey = DataManager.Current.OpenConnection(this);
                        adapter.Update(_table);
                    }
                    finally
                    {
                        DataManager.Current.CloseConnection(ckey);
                    }
                }

                // Wrap up the proxy operation
                if (ProxyServer.InProgress)
                {
                    adapter.RowUpdated -= updatedHander;
                    ProxyServer.Current.Result[ProxyServer.Current.CurrentAction].AddData("updated", updatedRowsTable);
                }
            }
            else
            {
                ProxyRequestAction action = ProxyClient.Request.AddAction(this, MethodInfo.GetCurrentMethod());
                action.OnComplete = delegate()
                {
                    DataTable updated      = ProxyClient.Result[action].GetData <DataTable>("updated");
                    bool      usingInnerID = updated.Columns.Contains(Const.InnerIDColumn);
                    if (!usingInnerID)
                    {
                        throw new Exception("not using inner ID!!!");
                    }

                    // Go over each row and find matching rows
                    for (int i = 0; i < updated.Rows.Count; i++)
                    {
                        bool    merged     = false;
                        DataRow updatedRow = updated.Rows[i];
                        object  testID     = usingInnerID ? updatedRow[Const.InnerIDColumn] : null;
                        if (testID is int)
                        {
                            int       innerID = (int)testID;
                            DataRow[] rs      = _table.Select(String.Format("{0} = {1}", Const.InnerIDColumn, innerID));
                            if (rs.Length > 0)
                            {
                                // If a row with a matching innerID is found, merge the values and accept changes
                                DataRow row = rs[0];
                                row.ItemArray = updatedRow.ItemArray;
                                row.AcceptChanges();
                                merged = true;
                            }
                        }

                        // TODO: make sure we shouldn't be clearing the table before adding unidentified rows
                        if (!merged)
                        {
                            // Insert the new row at the same index
                            DataRow newRow = _table.NewRow();
                            newRow.ItemArray = updatedRow.ItemArray;
                            _table.Rows.InsertAt(newRow, i);

                            DataItem newItem = NewItem(newRow);
                            _innerList.Insert(i, newItem);

                            if (_hash != null)
                            {
                                _hash.Add(GetPrimaryKeyValue(newItem), newItem);
                            }
                        }
                    }
                };
            }
        }