2017-05-07 9 views
1

ノードv6.9.5のExpress v4.15.2サーバーでBookshelf v0.10.3をKnex v0.12.9とともに使用しています。トランザクションに挿入した後に1対多の関係を保存する方法

identityテーブルを持つuserテーブルを持ち、identity_userテーブルで結合しています。テーブルはKnexを使用して作成されています。私は、新しいユーザーと単一のトランザクションでIDを挿入しようとしている、私のcreateUser機能で

bookshelf.plugin([ 'registry', 'bookshelf-camelcase' ]); 

const Identity = bookshelf.model('Identity', { 
    tableName: 'identity', 

    user() { 
    return this.belongsTo('User', 'identity_user'); 
    } 
}); 

const User = bookshelf.model('User', { 
    tableName: 'user', 

    initialize() { 
    this.on('saving', model => { 
     if (model.hasChanged('username')) { 
     return model.set('username', String(model.attributes.username).toLowerCase()); 
     } 
    }); 
    this.on('saving', model => { 
     if (model.hasChanged('password')) { 
     return bcrypt.hash(model.attributes.password, 10) 
      .then(hash => model.set('password', hash)); 
     } 
    }); 
    }, 

    identities() { 
    return this.hasMany('Identity', 'identity_user'); 
    } 
}); 

Promise.all([ 
    knex.schema.createTable('user', table => { 
    table.increments('id'); 
    table.string('username'); 
    table.string('password'); 
    table.unique('username'); 
    }), 
    knex.schema.createTable('identity', table => { 
    table.increments('id'); 
    table.string('type'); 
    table.string('value'); 
    }), 
    knex.schema.createTable('identity_user', table => { 
    table.integer('user_id').references('user.id'); 
    table.integer('identity_id').references('identity.id'); 
    table.unique(['user_id', 'identity_id']); 
    }) 
]); 

マイ本棚モデルは、このように見えます。

function createUser(req, res, next) { 
    const { email, username, password } = req.body; 

    // some data validation 

    return bookshelf.transaction((t) => { 
    return new User({ username, password }).save(null, { transacting: t }) 
     .then(user => new Identity({ type: 'email', value: email }).save({ userId: user.attributes.id }, { transacting: t })) 
     .then(() => res.sendStatus(204)) 
     .catch(err => { 
     // handle PostgreSQL unique violation error 
     }); 
    }); 
} 

私は、サーバーを実行して、新しいユーザーを登録しようとすると、私は次のエラーを取得する:

insert into "identity" ("type", "user_id", "value") values ($1, $2, $3) returning "id" - column "user_id" of relation "identity" does not exist { error: insert into "identity" ("type", "user_id", "value") values ($1, $2, $3) returning "id" - column "user_id" of relation "identity" does not exist 

これはPostgreSQLのエラー(コード42703 - 未定義の列)ですが、すべてがいるようです正しくセットアップしてください。私は実際にこれについて別の目を使用することができます。私は何が欠けていますか?

ありがとうございます!

答えて

1

ブックシェルフが「userId」がIdentityに挿入され、「user_id」と列名が推測されたためです。しかし、あなたが代わりにattach()を使用する必要がM×Nの関係に接続するために:

function createUser(req, res, next) { 
    const { email, username, password } = req.body; 

    // some data validation 

    return bookshelf.transaction((t) => { 
    return new User({ username, password }) 
     .save(null, { transacting: t }) 
     .then(user => new Identity({ type: 'email', value: email }) 
     .save(null, { transacting: t })) 
     .then(identity => user.identities() 
     .attach(identity.id, { transacting: t })); 
    }) 
    .then(() => res.sendStatus(204)) 
    .catch(err => { 
    // handle PostgreSQL unique violation error 
    }); 
} 

も私のために働くように見える変化は直接モデルを(例えば.attach(identity, { transacting: t }))を添付することですが、このアプローチは、文書によってサポートされていません。モデルとしてマッピングされる結合テーブルを必要とthrough()コールを、使用している場合

編集私はあなたのモデルの定義に2つのエラーを見落としてきた、hasMany()はM×Nの関係にマッピングされます。上記の場合、単純な 'belongsToMany() `呼び出しを使用すれば十分だと思います。

user() { 
    return this.belongsToMany('User'); 
} 

identities() { 
    return this.belongsToMany('Identity'); 
} 

EDIT2::だからにより、あなたの関係の定義を交換するトランザクション・スコープの外にcatch()を移動し、その例外が自動的にロールバックをトリガーします。

編集3:Flatter then()トランザクションスコープから削除されたチェーンと非dbのもの。

+0

お返事ありがとうございます。私はこれを試みたが、得た: "TypeError:user.identities(...)。attachは関数ではありません"。より複雑なことは、関係がリンクテーブルに追加されていないにもかかわらず、ユーザーとIDが両方とも作成されたという事実でした。キャッチの変更を手動でロールバックする必要がありますか? –

+0

申し訳ありませんが、あなたのモデル定義で2つのエラーを見落としました。 – flaviodesousa

+0

トランザクションスコープ 'bookshelf.transaction(t => {<ここにスコープ>})'内で例外がキャッチされない場合、トランザクションは自動的にロールバックされます。しかし、キャッチされた(そして再投げられない)場合、コミットは自動的にブックシェルフによってトリガーされます – flaviodesousa

関連する問題