/// <summary>
        /// Save the specified data of <see cref="IInternalState"/> into database.
        /// </summary>
        /// <param name="query">The <see cref="IAdfQuery"/> that defines the datasource name and query statement.</param>
        /// <param name="data">The data of <see cref="IInternalState"/> that needs to be saved.</param>
        /// <returns>True if data is successfully saved; otherwise, false. 
        /// This method also returns false if <see cref="IAdfQuery"/> or <see cref="IInternalState"/> is null.</returns>
        /// <exception cref="System.InvalidOperationException">The current state of the connection is closed.</exception>
        /// <exception cref="System.Data.DBConcurrencyException">An attempt to execute an INSERT, UPDATE, or DELETE statement resulted in zero records affected.</exception>
        public bool Save(IAdfQuery query, IInternalState data)
        {
            if (query == null) throw new ArgumentNullException("query");
            if (data == null) throw new ArgumentNullException("data");

            if (!data.IsAltered) return true;

            var state = data as DictionaryState;
            if (state == null) throw new InvalidOperationException("State is not a " + typeof(DictionaryState));

            var table = query.Tables[0];

            var q = new AdfQuery()
                .From(table);

            q.QueryType = state.IsNew ? QueryType.Insert : QueryType.Update;

            foreach (var col in state)
            {
                if (col.Key.IsAutoIncrement || col.Key.IsTimestamp) continue;                  // auto increment fields are not saved
                if (col.Key.IsIdentity && !state.IsNew) continue;       // primary key is not saved when object is not new

                q.Selects.Add(new Expression { Column = col.Key, Type = ExpressionType.Column });
                q.Wheres.Add(new Where { Column = col.Key, Parameter = new Parameter(col.Value, ParameterType.QueryParameter) });
            }

            if (!state.IsNew)
            {
                var timestamp = state.Keys.FirstOrDefault(col => col.IsTimestamp);
                if (timestamp == null) throw new InvalidOperationException("Cannot save this state as it does not have a timestamp");

                q
                    .Where(timestamp).IsEqual(state[timestamp])
                    .Where(state.PrimaryKey).IsEqual(state[state.PrimaryKey]);
            }

            return RunSave(state, q);
        }