public DbCommand BuildInsertCommand(DbProviderFactoryAdapter provider, object data, object keyData, Core.SQL.OnConflictOption option)
        {
            Debug.Assert(data != null);

            DbCommand command = provider.CreateCommand();

            var columnNames = new List<string>();
            var valueExpressions = new List<string>();

            if(keyData != null)
            {
                var keyField = EntityDescription.Fields.PrimaryKeyField;
                if (keyField != null)
                {
                    columnNames.Add(keyField.Name);
                    valueExpressions.Add(keyField.SQLPramName);

                    var pram = provider.CreateParameter(keyField.SQLPramName, keyData);
                    command.Parameters.Add(pram);
                }
                else
                {
                    throw new InvalidOperationException("keyData provided but type has no key field");
                }
            }

            foreach (FieldAttribute field in EntityDescription.Fields.GetPersistedFields(false, PersistanceFlags.OnInsert))
            {
                columnNames.Add(field.Name);
                valueExpressions.Add(field.SQLPramName);

                object value = field.GetFieldValueOrDefault(data);
                DbParameter pram = provider.CreateParameter(field.SQLPramName, value);
                command.Parameters.Add(pram);
            }

            var builder = new SQLInsertCommand
            {
                TableName = EntityDescription.SourceName,
                ConflictOption = option,
                ColumnNames = columnNames,
                ValueExpressions = valueExpressions
            };

            command.CommandText = builder.ToString();

            return command;
        }
        public DbCommand BuildSelectCommand(DbProviderFactoryAdapter provider, SelectClause clause)
        {
            Debug.Assert(_selectCommand != null);

            this._selectCommand.Clause = clause;

            string query = _selectCommand.ToSQL();

            DbCommand command = provider.CreateCommand(query);
            return command;
        }
        protected DbCommand BuildSQLDeleteCommand(DbProviderFactoryAdapter provider, string keyFieldName, object keyValue)
        {
            Debug.Assert(keyValue != null);
            Debug.Assert(!string.IsNullOrEmpty(keyFieldName));

            string query = string.Format(@"DELETE FROM {0} WHERE {1} = @keyValue;", EntityDescription.SourceName, keyFieldName);

            var command = provider.CreateCommand(query);

            command.Parameters.Clear();
            command.Parameters.Add(provider.CreateParameter("@keyValue", keyValue));
            return command;
        }
        public DbCommand BuildUpdateCommand(DbProviderFactoryAdapter provider, object data, object keyData, Core.SQL.OnConflictOption option)
        {
            Debug.Assert(data != null);
            Debug.Assert(EntityDescription.Fields.PrimaryKeyField != null);

            DbCommand command = provider.CreateCommand();

            var columnNames = new List<string>();
            var columnExpressions = new List<string>();
            foreach (FieldAttribute field in EntityDescription.Fields.GetPersistedFields(true, PersistanceFlags.OnUpdate))
            {
                columnNames.Add(field.Name);
                columnExpressions.Add(field.SQLPramName);

                object value = field.GetFieldValueOrDefault(data);
                DbParameter pram = provider.CreateParameter(field.SQLPramName, value);
                command.Parameters.Add(pram);
            }

            PrimaryKeyFieldAttribute keyField = EntityDescription.Fields.PrimaryKeyField;
            DbParameter p = provider.CreateParameter(keyField.SQLPramName, keyData);
            command.Parameters.Add(p);

            var where = new WhereClause(keyField.Name + " = " + keyField.SQLPramName);

            var expression = new SQLUpdateCommand()
            {
                TableName = EntityDescription.SourceName,
                ColumnNames = columnNames,
                ValueExpressions = columnExpressions,
                ConflictOption = option,
                Where = where
            };

            command.CommandText = expression.ToString();

            return command;
        }
        public DbCommand BuildSQLDeleteCommand(DbProviderFactoryAdapter provider, object data)
        {
            PrimaryKeyFieldAttribute keyFieldInfo = EntityDescription.Fields.PrimaryKeyField;

            if (keyFieldInfo == null) { throw new InvalidOperationException("type doesn't have primary key field"); }
            object keyValue = keyFieldInfo.GetFieldValue(data);

            return this.BuildSQLDeleteCommand(provider, keyFieldInfo.Name, keyValue);
        }
        public DbCommand BuildSelectLegacy(DbProviderFactoryAdapter provider, string selection)
        {
            Debug.Assert(_selectCommand != null);

            this._selectCommand.Clause = new LegacySelectPlaceholder() { Index = 0 };

            string query = String.Format(_selectCommand.ToSQL(), selection);

            DbCommand command = provider.CreateCommand(query);
            return command;
        }
        public void VerifyCommandSyntex(DbProviderFactoryAdapter provider, DbCommand command)
        {
            command.CommandText = "EXPLAIN " + command.CommandText;

            using (DbConnection conn = provider.CreateConnection())
            {
                conn.ConnectionString = "Data Source =:memory:; Version = 3; New = True;";
                conn.Open();

                command.Connection = conn;

                try
                {
                    command.ExecuteNonQuery();
                }
                catch(DbException ex)
                {
                    Assert.DoesNotContain("syntax ", ex.Message, StringComparison.InvariantCultureIgnoreCase);
                }

            }
        }