デフォルトの INSERT クエリは、
* デフォルト値を持たない
* オートインクリメントではない
の 2 つの条件を満たすフィールドで構成されるようになっています。
コードは下記のとおりです。(Subversion trunk より)
Piece/ORM/Mapper/Generator.php:
function _generateDefaultInsertQuery()
{
$fields = array();
foreach ($this->_metadata->getFieldNames() as $fieldName) {
if (!$this->_metadata->hasDefault($fieldName) && !$this->_metadata->isAutoIncrement($fieldName)) {
$fields[] = $fieldName;
}
}
return 'INSERT INTO ' . $this->_metadata->getTableName() . ' (' . implode(", ", $fields) . ') VALUES (' . implode(', ', array_map(create_function('$f', "return '\$' . Piece_ORM_Inflector::camelize(\$f, true);"), $fields)) . ')';
}
念のため、こちらでも下記テーブル定義によって確認しましたが再現すること
ができませんでした。artist_id が該当するフィールドになります。
テーブル定義の SQL:
CREATE TABLE album (
id int(11) NOT NULL AUTO_INCREMENT,
artist_id INTEGER UNSIGNED NOT NULL,
name varchar(255) NOT NULL,
version int(11) NOT NULL DEFAULT '0',
rdate datetime NOT NULL,
mdate timestamp,
PRIMARY KEY(id)
);
mysql コマンドから確認したテーブル定義:
mysql> desc album;
+-----------+------------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+------------------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| artist_id | int(10) unsigned | NO | | | |
| name | varchar(255) | NO | | | |
| version | int(11) | NO | | 0 | |
| rdate | datetime | NO | | | |
| mdate | timestamp | NO | | CURRENT_TIMESTAMP | |
+-----------+------------------+------+-----+-------------------+----------------+
6 rows in set (0.01 sec)
生成された SQL:
INSERT INTO album (artist_id, name, rdate) VALUES ($artistId, $name, CURRENT_TIMESTAMP)
原因として考えられるのは、何らかの理由によりテーブル定義の SQL と実際
のスキーマが同期していないことです。
可能であれば、示して頂いたテーブル定義の SQL を使って、テーブル名を変
更した上でテーブルを作成し、生成される SQL を確認頂けないでしょうか。
以上、よろしくお願いいたします。
--
KUBO Atsuhiro e-mail: ku...@iteman.jp
katarou さんは書きました:
> 行いたかったのはチェックボックスの値をテーブルに保存する場合、フラグとして0か1を持たせたくdefault 0をつけていました。
> 確認すると全部デフォルト値となっていたので、相談した次第です。
>
> defaultが指定されているフィールドは値を渡されてもdefaultが優先されるということですね。
> 処理を考えてみたいと思います。
なるほど、理解いたしました。
INSERT クエリがひとつでも問題なければ、insert のクエリを再定義するとい
いでしょう。その場合は、必ず対象フィールドの値が設定されるように、オブ
ジェクトの対象プロパティに必ず値を設定するか、SQL側で対象プロパティの
値によって条件分岐することで対応してください。
ちなみに、プリペアドステートメントのプレースホルダと異なり、Piece_ORM
のクエリ内の変数は、左辺値としても使用可能です。
INSERT クエリが複数必要と思われる場合は、insert には手を付けずに、
insertXXX のように insert で始まるメソッドを定義するといいでしょう。
なお、メソッドの再定義は下記のいずれも可能となっています。
* findAllXXX
* findOneXXX
* findXXX
* insertXXX
* updateXXX
* deleteXXX
KUBO Atsuhiro さんは書きました:
> なお、メソッドの再定義は下記のいずれも可能となっています。
すみません、
「なお、メソッドの定義は下記のいずれも可能となっています。」が正解です。
メソッドは、それが再定義かどうかにかかわらず定義可能です。
要望を頂きましてありがとうございます。
katarou さんは書きました:
> 希望なのですが
> 通常のSQLのdefaultはsql内に該当フィールドがあればその値を、そうでなければdefaultを使うという仕様が一般的かと思います。
> マッパーにたとえば、insertByDynamincFieldsというメソッドがあり、引数で
> $value = $mapper->createObject();
> $value->foo = 1;
> $value->bar = 2;
> $mapper->insertByDynamincFields($value);
> とやれば、与えられたフィールドでinsertをおこなうメソッドがあれば、有用ではないかと思うのですがいかがでしょうか?
こちらについては、SQL で対象の変数を評価することによって実現できるこ
とから、機能としての採用は見送りたいと思います。
> あと、Finderについても、複数条件検索の場合はFinderを定義しなければならないと思いますが、
> 同様にfindBy(All)DynamincFieldsというメソッドがあり、
> $value->foo = 1;
> $value->bar = 2;
> $mapper->findByDynamincFields($value);
> とやれば、複数条件で検索ができるとか、、
> Finderを定義しなくてよい分コーディングが楽になるような気がしてます。デフォルトなのでAND条件、比較は'='で。
> それ以外のケース(Between, OR結合 , '<' , '>'など)が発生した場合は別定義でやればよいかと。
こちらについては、2 つの方法があります。ひとつは、SQL を使うことです。
(推奨) 例えば下記のようなファインダ定義によって、簡単に複数条件検索を
実現することができます。
- name: findAllByCriteria
query: |
SELECT
*
FROM
person
WHERE
(($firstName IS NULL OR $firstName = '') OR first_name LIKE $firstName)
AND (($lastName IS NULL OR $lastName = '') OR last_name LIKE $lastName)
AND (($loginName IS NULL OR $loginName = '') OR login_name LIKE $loginName)
もうひとつは、何らかの手段によって自分で SQL を構築することです。
下記のメソッドを使って任意の SQL を実行し結果を取得することができます。
* findAllWithQuery()
* findWithQuery()
* findOneWithQuery()
SQL の構築には、PEAR の (M) DB_QueryTool や
http://d.hatena.ne.jp/fbis/20070613/1181737366 などを使うといいでしょう。
こちらについても機能としての採用は見送りたいと思います。
以上、よろしくお願いいたします。