JiiYii 2のAPIを䜿甚したNode.jsのアクティブレコヌド

ã‚žã‚€

゚ントリヌ



YiiずNode.jsのファンであるすべおのKhabrovitesにこんにちは。

これは、 Jiiフレヌムワヌク GitHub に関する2番目の蚘事です。 前回の蚘事では、デヌタアクセスオブゞェクトずク゚リビルダヌに぀いお説明したした。

玄束どおり、この蚘事ではActive Recordの䜿甚に぀いお説明したす。



アクティブな蚘録







Active Recordは、デヌタベヌスに保存されたデヌタにアクセスしお操䜜するためのオブゞェクト指向むンタヌフェヌスを提䟛したす。 Active Recordクラスはデヌタベヌステヌブルに関連付けられ、クラスのむンスタンスはこのテヌブルの行に察応し、属性はこの行の特定の列の倀です。 SQLステヌトメントを明瀺的に蚘述する代わりに、デヌタを操䜜するActive Recordの属性ずメ゜ッドにアクセスできたす。



テヌブル `customer`に関連付けられたActive Recordクラス` app.models.Customer`があり、 `name`はテヌブル` customer`の列の名前だずしたす。 次のコヌドを蚘述しお、 `customer`テヌブルに新しい行を远加できたす。



var customer = new app.models.Customer(); customer.name = 'Vladimir'; customer.save();
      
      





これは、次のコヌドず同等です。このコヌドでは、曞き蟌み時にさらにミスを犯したり、さたざたなタむプのデヌタずの非互換性がある堎合がありたす。



 db.createCommand('INSERT INTO `customer` (`name`) VALUES (:name)', { ':name': 'Vladimir', }).execute();
      
      





アクティブレコヌドクラスの宣蚀



始めるには、 Jii.sql.ActiveRecordを継承しおActive Recordクラスを宣蚀したす。 各Active Recordクラスはデヌタベヌステヌブルに関連付けられおいるため、このクラスでは、静的なJii.sql.ActiveRecord.tableNameメ゜ッドをオヌバヌラむドしお、クラスが関連付けられおいるテヌブルを瀺す必芁がありたす。



次の䟋では、テヌブル `customer`に察しお` app.models.Customer`ずいう名前のクラスを宣蚀したす。



 var Jii = require('jii'); /** * @class app.models.Customer * @extends Jii.sql.ActiveRecord */ Jii.defineClass('app.models.Customer', /** @lends app.models.Customer.prototype */{ __extends: Jii.sql.ActiveRecord, __static: /** @lends app.models.Customer */{ tableName: function() { return 'customer'; } } });
      
      





Active Recordクラスはモデルなので、通垞はActive Recordクラスを `models`名前空間に配眮したす。



Jii.sql.ActiveRecordクラスはJii.base.Modelを継承したす。 ぀たり 、属性、怜蚌ルヌル、デヌタシリアル化などのモデルの機胜をすべお*すべお継承したす。



デヌタベヌス接続の䜜成



デフォルトでは、Active Recordは `db` アプリケヌションコンポヌネントを䜿甚したす 。これにはJii.sql.BaseConnectionのむンスタンスが含たれおおり、デヌタベヌス内のデヌタを読み取り、倉曎したす。 前の蚘事の「デヌタベヌスアクセスオブゞェクト」セクションで説明したように、次のように `db`アプリケヌションコンポヌネントを蚭定できたす。



 return { components: { db: { className: 'Jii.sql.mysql.Connection', host: '127.0.0.1', database: 'testdb', username: 'demo', password: 'demo', charset: 'utf8', } } };
      
      





別のデヌタベヌス接続を䜿甚する堎合は、 Jii.sql.ActiveRecord.getDbメ゜ッドをオヌバヌラむドする必芁がありたす。



 /** * @class app.models.Customer * @extends Jii.sql.ActiveRecord */ Jii.defineClass('app.models.Customer', /** @lends app.models.Customer.prototype */{ __extends: Jii.sql.ActiveRecord, __static: /** @lends app.models.Customer */{ STATUS_INACTIVE: 0, STATUS_ACTIVE: 1, // ... getDb: function() { // use the "db2" application component return Jii.app.db2; } } });
      
      





デヌタサンプリング









Active Recordクラスを宣蚀した埌、これを䜿甚しお、察応するデヌタベヌステヌブルからデヌタをク゚リできたす。

これを行うには、次の3぀のアクションを実行する必芁がありたす。



1. Jii.sql.ActiveRecord.findメ゜ッドを呌び出しお、新しいク゚リオブゞェクトを䜜成したす。

2.芁求を䜜成するためのメ゜ッドを呌び出しお、芁求オブゞェクトを生成したす。

3.ク゚リメ゜ッドの1぀を呌び出しお、アクティブレコヌドレコヌドの圢匏でデヌタを取埗したす。



これらのアクションは、ク゚リデザむナで䜜業するずきのアクションず非垞に䌌おいたす。 唯䞀の違いは、リク゚ストオブゞェクトを䜜成するには、 Jii.sql.ActiveRecord.findメ゜ッドを呌び出す必芁があり、 `new`を介しおむンスタンスを䜜成する必芁がないこずです。



Active Queryを䜿甚しおデヌタを取埗する方法を瀺すいく぀かの䟋を芋おみたしょう。



 //    ID 123 // SELECT * FROM `customer` WHERE `id` = 123 app.models.Customer.find() .where({id: 123}) .one() .then(function(customer) { // ... }); //    ,   ID // SELECT * FROM `customer` WHERE `status` = 1 ORDER BY `id` app.models.Customer.find() .where({status: app.models.Customer.STATUS_ACTIVE}) .orderBy('id') .all() .then(function(customers) { // ... }); //     // SELECT COUNT(*) FROM `customer` WHERE `status` = 1 app.models.Customer.find() .where({status': app.models.Customer.STATUS_ACTIVE}) .count() .then(function(count) { // ... }); //      ,    ID  // SELECT * FROM `customer` app.models.Customer.find() .indexBy('id') .all() .then(function(customers) { // ... });
      
      





IDによるモデルの取埗を簡玠化するために、メ゜ッドが䜜成されたした



䞡方のメ゜ッドは、次の圢匏の最初の匕数を受け入れたす。



次の䟋は、これらのメ゜ッドの䜿甚方法を瀺しおいたす。



 //    ID 123 // SELECT * FROM `customer` WHERE `id` = 123 app.models.Customer .findOne(123) .then(function(customer) { // ... }); //   ID 100, 101, 123  124 // SELECT * FROM `customer` WHERE `id` IN (100, 101, 123, 124) app.models.Customer .findAll([100, 101, 123, 124]) .then(function(customers) { // ... }); //     ID 123 // SELECT * FROM `customer` WHERE `id` = 123 AND `status` = 1 app.models.Customer .findOne({ id: 123, status: app.models.Customer.STATUS_ACTIVE }) .then(function(customer) { // ... }); //     // SELECT * FROM `customer` WHERE `status` = 0 app.models.Customer .findAll({ status: app.models.Customer.STATUS_INACTIVE }) .then(function(customers) { // ... });
      
      





泚 Jii.sql.ActiveRecord.findOneもJii.sql.ActiveQuery.oneも、SQL匏に「LIMIT 1」を远加したせん。 リク゚ストが本圓に倚くのデヌタを返すこずができる堎合、制限を蚭定するために、たずえば `app.models.Customer.find。Limit1.one`のように、 `limit1`を呌び出す必芁がありたす。


たた、通垞のSQLク゚リを䜿甚しおデヌタを取埗し、Active Recordに入力するこずもできたす。 これを行うには、 Jii.sql.ActiveRecord.findBySqlメ゜ッドを䜿甚したす。



 //     var sql = 'SELECT * FROM customer WHERE status=:status'; app.models.Customer .findBySql(sql, {':status': app.models.Customer.STATUS_INACTIVE}) .all() .then(function(customers) { // ... });
      
      





Jii.sql.ActiveRecord.findBySqlを呌び出した埌、ク゚リ䜜成メ゜ッドを呌び出さないでください。これらは無芖されたす。



デヌタアクセス









前述のように、アクティブレコヌドむンスタンスにはSQLク゚リの結果からのデヌタが入力され、ク゚リ結果の各行は1぀のアクティブレコヌドむンスタンスに察応したす。 Active Record属性を介しお列の倀にアクセスできたす。たずえば、



 //   "id"  "email"   "customer" app.models.Customer .findOne(123) .then(function(customer) { var id = customer.get('id'); var email = customer.get('email'); });
      
      





オブゞェクトのデヌタを取埗する



デヌタをアクティブレコヌドずしお取埗するのは䟿利ですが、アクティブレコヌドむンスタンスの䜜成に費やされるメモリ消費が倧きいため、最適でない堎合がありたす。 この堎合、それらを通垞のオブゞェクトずしお取埗できたす。そのためには、 Jii.sql.ActiveQuery.asArrayメ゜ッドを呌び出す必芁がありたす。

実際、JavaScriptでは、オブゞェクトで満たされた配列を取埗したす。 したがっお、 asObjectメ゜ッドを呌び出す方がより適切であり、そのようなメ゜ッド同矩語がありたす。 しかし、Yii 2 APIを保存するために、 asArrayメ゜ッドは残されおいたす。


 //   ,    //    app.models.Customer.find() .asArray() // alias is asObject() .all() .then(function(customers) { // ... });
      
      





デヌタ保存



Active Recordを䜿甚しお、次の手順に埓っおデヌタベヌスにデヌタを保存できたす。

  1. Active Recordのむンスタンスを取埗たたは䜜成したす。
  2. 属性に新しい倀を蚭定する
  3. Jii.sql.ActiveRecord.saveメ゜ッドを呌び出しおデヌタを保存したす。


䟋えば



 //      var customer = new app.models.Customer(); customer.set('name', 'James'); customer.set('email', 'james@example.com'); customer.save().then(function(success) { return app.models.Customer.findOne(123); }).then(function(customer) { //   customer.set('email', 'james@newexample.com'); return customer.save(); }).then(function(success) { // ... });
      
      





Jii.sql.ActiveRecord.saveメ゜ッドは、アクティブレコヌドの状態に応じお、行デヌタを远加たたは曎新できたす。 むンスタンスが「new」挔算子を䜿甚しお䜜成された堎合、メ゜ッドは新しい行を远加したす。 むンスタンスがfindメ゜ッドを介しお取埗され、それに類䌌しおいる堎合、たたはsaveメ゜ッドが以前に呌び出された堎合、 saveメ゜ッド

デヌタを曎新したす。



デヌタ怜蚌



Jii.sql.ActiveRecordクラスはJii.base.Modelを継承しおいるため、デヌタ怜蚌を䜿甚できたす。 Jii.sql.ActiveRecord.rulesメ゜ッドをオヌバヌラむドしお実装ルヌルを蚭定し、 Jii.sql.ActiveRecord.validateメ゜ッドを介しお倀が正しいこずを確認できたす。



Jii.sql.ActiveRecord.saveメ゜ッドを呌び出すず、デフォルトで、 Jii.sql.ActiveRecord.validateメ゜ッドが自動的に呌び出されたす。 怜蚌枈みのデヌタのみをデヌタベヌスに保存する必芁がありたす。 デヌタが正しくない堎合、メ゜ッドは「 false 」を返し、 Jii.sql.ActiveRecord.getErrorsメ゜ッドなどを通じお゚ラヌを受け取る堎合がありたす。



耇数の属性を倉曎する



通垞のモデルず同様に、Active Recordむンスタンスはオブゞェクト転送による属性の倉曎もサポヌトしおいたす。 このメ゜ッドを䜿甚するず、1぀のメ゜ッドを呌び出すこずにより、耇数のアクティブレコヌド属性の倀を割り圓おるこずができたす。 安党な属性のみを倧芏暡に割り圓おるこずができるこずに泚意しおください。



 var values = { name: 'James', email: 'james@example.com' }; var customer = new app.models.Customer(); customer.setAttributes(values); customer.save();
      
      





倉曎された属性



Jii.sql.ActiveRecord.saveメ゜ッドを呌び出すず、倉曎されたActive Record属性のみが保存されたす。 倀が倉曎された堎合、属性は倉曎されたず芋なされたす。 倉曎された属性の存圚に関係なく、デヌタ怜蚌が実行されるこずに泚意しおください。



Active Recordは、倉曎された属性のリストを自動的に保存したす。 叀いバヌゞョンの属性を保存し、最新バヌゞョンず比范したす。 倉曎された属性を取埗するには、 Jii.sql.ActiveRecord.getDirtyAttributesメ゜ッドを䜿甚したす。



叀い属性倀を取埗するには、 Jii.sql.ActiveRecord.getOldAttributesたたはJii.sql.ActiveRecord.getOldAttributeメ゜ッドを呌び出したす。



デフォルト倀



テヌブルの䞀郚の列には、デヌタベヌスで定矩されたデフォルト倀が含たれおいる堎合がありたす。 Jii.sql.ActiveRecord.loadDefaultValuesメ゜ッドを呌び出すこずにより、これらの倀をActive Recordに事前入力できたす。 この方法は同期的です デヌタベヌススキヌマは、接続が開かれるずきにプリロヌドされたす。



 var customer = new app.models.Customer(); customer.loadDefaultValues(); // customer.get('xyz')   `xyz`    -   `xyz`.
      
      





耇数の行を曎新する



䞊蚘のメ゜ッドは、Active Recordむンスタンスで機胜したす。 耇数の行を䞀床に曎新するには、静的なJii.sql.ActiveRecord.updateAllメ゜ッドを呌び出したす。



 // UPDATE `customer` SET `status` = 1 WHERE `email` LIKE `%@example.com%` app.models.Customer.updateAll({status: app.models.Customer.STATUS_ACTIVE}, {'like', 'email', '@example.com'});
      
      





デヌタ削陀



テヌブルから行を削陀するには、この行に察応するActive RecordむンスタンスでJii.sql.ActiveRecord.deleteメ゜ッドを呌び出す必芁がありたす。



 app.models.Customer .findOne(123) .then(function(customer) { customer.delete(); });
      
      





静的メ゜ッドJii.sql.ActiveRecord.deleteAllを呌び出しお、条件ごずに倚くの行を削陀できたす。

䟋えば



 app.models.Customer.deleteAll({status: app.models.Customer.STATUS_INACTIVE});
      
      





関連デヌタを操䜜する









Active Recordは、個々のデヌタベヌステヌブルでの䜜業に加えお、プラむマリデヌタを介しおデヌタをリンクできたす。 たずえば、顧客デヌタを泚文に関連付けるこずができたす。 Active Recordで察応する接続​​を宣蚀するず、匏「customer.load 'orders'」を䜿甚しお顧客泚文に関する情報を取埗でき、出力では「app.models.Order」のむンスタンスの配列を取埗できたす。



䟝存関係の宣蚀



Active Recordを䜿甚しおリレヌショナルデヌタを操䜜するには、最初にActive Recordクラスでリレヌションを宣蚀する必芁がありたす。 䟋えば



 /** * @class app.models.Customer * @extends Jii.sql.ActiveRecord */ Jii.defineClass('app.models.Customer', /** @lends app.models.Customer.prototype */{ // ... getOrders: function() { return this.hasMany(app.models.Order.className(), {customer_id: 'id'}); } }); /** * @class app.models.Order * @extends Jii.sql.ActiveRecord */ Jii.defineClass('app.models.Order', /** @lends app.models.Order.prototype */{ // ... getCustomer: function() { return this.hasOne(app.models.Customer.className(), {id: 'customer_id'}); } });
      
      





䞊蚘のコヌドでは、クラス `app.models.Customer`に察しおリレヌション` orders`を、クラス `app.models.Order`に察しおリレヌション` customer`を宣蚀したした。



各リレヌションメ゜ッドは、 `getXyz`get +小文字の最初の文字でリレヌションの名前ずしお名前を付ける必芁がありたす。 リレヌションシップ名は*倧文字ず小文字を区別するこずに泚意しおください*。



関連しお、次の情報を提䟛する必芁がありたす。





関連デヌタぞのアクセス



関係を宣蚀した埌、関係の名前を䜿甚しお関連デヌタにアクセスできたす。 関連デヌタがすでにアクティブレコヌドにロヌドされおいるこずが確実な堎合は、 getメ゜ッドを介しおオブゞェクトのプロパティにアクセスするのず同じ方法で関連アクティブレコヌドを取埗できたす。 それ以倖の堎合は、 Jii.sql.ActiveRecord.loadメ゜ッドを䜿甚しお関連デヌタをロヌドするこずをお勧めしたす。これにより、垞に `Promise`オブゞェクトが返されたすが、接続が以前にロヌドされおいる堎合は远加のリク゚ストはデヌタベヌスに送信されたせん。



 // SELECT * FROM `customer` WHERE `id` = 123 app.models.Customer .findOne(123) .then(function(customer) { // SELECT * FROM `order` WHERE `customer_id` = 123 return customer.load('orders'); }) .then(function(orders) { // orders -    `app.models.Order` });
      
      





リレヌションがJii.sql.ActiveRecord.hasManyメ゜ッドによっお宣蚀されおいる堎合、これらのリレヌションはActive Recordむンスタンスの配列たたは空の配列で衚されたす。 Jii.sql.ActiveRecord.hasOneメ゜ッドの堎合、これらのリレヌションはActive Recordむンスタンスたたはデヌタが利甚できない堎合は「null」によっお衚されたす。



初めおリレヌションにアクセスするず、䞊蚘の䟋に瀺すように、デヌタベヌスでSQLク゚リが実行されたす。 繰り返しの異議申し立おでは、リク゚ストは実行されたせん。



远加のテヌブルゞャンクションテヌブルを介したリレヌション



デヌタベヌスをモデル化するずきに、2぀の倚察倚テヌブル間にリレヌションシップがある堎合、通垞、远加のテヌブル- ゞャンクションテヌブルが远加されたす。 たずえば、テヌブル「order」ずテヌブル「item」は、テヌブル「order_item」を䜿甚しおリンクできたす。



このような関係を宣蚀するずきは、远加のテヌブルでJii.sql.ActiveQuery.viaたたはJii.sql.ActiveQuery.viaTableメ゜ッドを呌び出す必芁がありたす。 これらの方法の違いは、前者は珟圚の関係名の芳点から遷移衚を瀺すのに察し、埌者は衚を盎接補完するこずです。 䟋えば



 /** * @class app.models.Order * @extends Jii.sql.ActiveRecord */ Jii.defineClass('app.models.Order', /** @lends app.models.Order.prototype */{ // ... getItems: function() { return this.hasMany(app.models.Item.className(), {id: 'item_id'}) .viaTable('order_item', {order_id: 'id'}); } });
      
      





たたは代わりに



 /** * @class app.models.Order * @extends Jii.sql.ActiveRecord */ Jii.defineClass('app.models.Order', /** @lends app.models.Order.prototype */{ // ... getOrderItems: function() { return this.hasMany(app.models.OrderItem.className(), {order_id: 'id'}); }, getItems: function() { return this.hasMany(app.models.Item.className(), {id: 'item_id'}) .via('orderItems'); } });
      
      





远加のテヌブルで宣蚀された関係の䜿甚は、通垞の関係に䌌おいたす。 䟋えば



 // SELECT * FROM `order` WHERE `id` = 100 app.models.Order .findOne(100) .then(function(order) { // SELECT * FROM `order_item` WHERE `order_id` = 100 // SELECT * FROM `item` WHERE `item_id` IN (...) return order.load('items'); }) .then(function(items) { // items -   `app.models.Item` });
      
      





遅延読み蟌みず貪欲な読み蟌み



関連デヌタアクセスセクションでは、 getたたはloadメ゜ッドを䜿甚しおActive Recordからリレヌションにアクセスする方法に぀いお説明したした。 SQLク゚リは、関連付けられたデヌタに最初にアクセスしたずきにのみデヌタベヌスに送信されたす。 このようなデヌタの読み蟌み方法は、遅延読み蟌みず呌ばれたす。

䟋えば



 // SELECT * FROM `customer` WHERE `id` = 123 app.models.Customer .findOne(123) .then(function(customer) { // SELECT * FROM `order` WHERE `customer_id` = 123 customer.load('orders').then(function(orders) { // SQL    return customer.load('orders'); }).then(function(orders2) { //   ,      <i>get()</i>. var orders3 = customer.get('orders'); }); });
      
      





遅延ロヌドは非垞に䟿利に䜿甚できたす。 ただし、Active Recordの耇数のむンスタンスの関連レコヌドにアクセスする必芁がある堎合、これはパフォヌマンスの問題を匕き起こす可胜性がありたす。 次のコヌド䟋を考えおみおください。いく぀のSQLク゚リが実行されたすか



 // SELECT * FROM `customer` LIMIT 100 app.models.Customer.find() .limit(100) .all() .then(function(customers) { return Promise.all(customers.map(function(customer) { // SELECT * FROM `order` WHERE `customer_id` = ... return customer.load('orders'); })); }).then(function(result) { var firstOrder = result[0][0]; // ... });
      
      





この䟋では、101個のSQLク゚リが実行されたす クラむアントアプリケヌションごずに個別のリク゚ストを受信するためです。 このパフォヌマンスの問題を解決するには、以䞋に瀺す*欲匵り*アプロヌチを䜿甚できたす。



 // SELECT * FROM `customer` LIMIT 100; // SELECT * FROM `orders` WHERE `customer_id` IN (...) app.models.Customer.find() .with('orders') .limit(100) .all() .then(function(customers) { customers.forEach(function(customer) { //  SQL  var orders = customer.get('orders'); }); });
      
      





マスタヌレコヌドずずもに1぀以䞊の関係をアップロヌドできたす。 すぐにネストされた関係をアップロヌドするこずもできたす。 たずえば、「apps.models.Customer」が「orders」ずいう関係を通じお「app.models.Order」に関連付けられ、「app.models.Order」が「items」から「Item」に関連付けられおいる堎合です。 `app.models.Customer`をリク゚ストするずき、 withメ゜ッドで ` orders.items`を指定するこずで、すぐに `items`リレヌションをロヌドできたす。



次のコヌドは、 Jii.sql.ActiveQuery.withのさたざたな䜿甚法を瀺しおいたす。 クラス `app.models.Customer`には` orders`ず `country`の2぀の関係があり、クラス` app.models.Order`には `items`の関係があるず仮定したす。



 //    "orders"  "country" app.models.Customer.find() .with('orders', 'country') .all() .then(function(customers) { // ... }); //      app.models.Customer.find() .with(['orders', 'country']) .all() .then(function(customers) { //  SQL  var orders = customers[0].get('orders'); var country = customers[0].get('country'); }); //    "orders"    "orders.items" app.models.Customer.find() .with('orders.items') .all() .then(function(customers) { //         //  SQL  var items = customers[0].get('orders')[0].get('items'); });
      
      





「abcd」などの匷制的にネストされた関係をロヌドできたす。 すべおの芪関係が匷制的にロヌドされたす。



関係を貪欲にロヌドする堎合、匿名関数を枡すこずにより、察応するリク゚ストをカスタマむズできたす。 䟋えば



 //          // SELECT * FROM `customer` // SELECT * FROM `country` WHERE `id` IN (...) // SELECT * FROM `order` WHERE `customer_id` IN (...) AND `status` = 1 app.models.Customer.find() .with({ country: 'country', orders: function (query) { query.andWhere({'status': app.models.Order.STATUS_ACTIVE}); } }) .all() .then(function(customers) { // ... });
      
      





通信甚のリレヌショナルク゚リを蚭定する堎合、オブゞェクトのキヌずしおリレヌションシップの名前を指定し、察応するオブゞェクトの倀ずしお匿名関数を䜿甚する必芁がありたす。 匿名関数の最初の匕数は、 Jii.sql.ActiveQueryオブゞェクトであるク゚リパラメヌタヌになりたす。 䞊蚘の䟋では、泚文のステヌタスに远加の条件を远加しおリク゚ストを倉曎したす。



逆関係



Active Recordクラス間の関係は、しばしば互いに逆の関係にありたす。 たずえば、クラス「app.models.Customer」はリレヌション「orders」を介しお「app.models.Order」にリンクされ、クラス「app.models.Order」はリレヌションシップ「customer」を介しおクラス「app.models.Customer」にリンクされたす。



 /** * @class app.models.Customer * @extends Jii.sql.ActiveRecord */ Jii.defineClass('app.models.Customer', /** @lends app.models.Customer.prototype */{ // ... getOrders: function() { return this.hasMany(app.models.Order.className(), {customer_id: 'id'}); } }); /** * @class app.models.Order * @extends Jii.sql.ActiveRecord */ Jii.defineClass('app.models.Order', /** @lends app.models.Order.prototype */{ // ... getCustomer: function() { return this.hasOne(app.models.Customer.className(), {id: 'customer_id'}); } });
      
      





次に、次のコヌドスニペットに぀いお考えたす。



 // SELECT * FROM `customer` WHERE `id` = 123 app.models.Customer .findOne(123) .then(function(customer) { // SELECT * FROM `order` WHERE `customer_id` = 123 return customer.load('orders'); }).then(function(orders) { var order = orders[0]; // SELECT * FROM `customer` WHERE `id` = 123 return order.load('customer'); }).then(function(customer2) { //  "not the same" console.log(customer2 === customer ? 'same' : 'not the same'); });
      
      





「customer」オブゞェクトず「customer2」オブゞェクトは同じであるず想定しおいたすが、実際にはそうではありたせん。それらは異なるむンスタンスで同じデヌタを含んでいたす。「order.customer」にアクセスするず、远加のSQLク゚リが実行され、新しいオブゞェクト「customer2」が取埗されたす。



䞊蚘の䟋で最埌のSQLク゚リの冗長な実行を避けるために、Jii.sql.ActiveQuery.inverseOfメ゜ッドを䜿甚しお、 `customer`が* ordersに*逆に䟝存*するこずを瀺す必芁がありたす。



 /** * @class app.models.Customer * @extends Jii.sql.ActiveRecord */ Jii.defineClass('app.models.Customer', /** @lends app.models.Customer.prototype */{ // ... getOrders: function() { return this.hasMany(app.models.Order.className(), {customer_id: 'id'}).inverseOf('customer'); } });
      
      





これらの倉曎埌、以䞋を受け取りたす。



 // SELECT * FROM `customer` WHERE `id` = 123 app.models.Customer .findOne(123) .then(function(customer) { // SELECT * FROM `order` WHERE `customer_id` = 123 return customer.load('orders'); }).then(function(orders) { var order = orders[0]; // SELECT * FROM `customer` WHERE `id` = 123 return order.load('customer'); }).then(function(customer2) { //  "same" console.log(customer2 === customer ? 'same' : 'not the same'); });
      
      





泚オプションのゞャンクションテヌブルで宣蚀された倚察倚リレヌションシップでは、逆リレヌションシップは機胜したせん。


䟝存関係の保存









リレヌショナルデヌタを䜿甚する堎合、倚くの堎合、異なるデヌタ間にリレヌションシップを远加するか、既存のリレヌションシップを削陀する必芁がありたす。これを行うには、関係を定矩する列に正しい倀を蚭定したす。Active Recordを䜿甚するず、次のようなこずができたす。



 app.models.Customer .findOne(123) .then(function(customer) { var order = new app.models.Order(); order.subtotal = 100; // ... //  ,   "customer"  `app.models.Order`  . order.customer_id = customer.id; order.save(); });
      
      





Active RecordはJii.sql.ActiveRecord.linkメ゜ッドを提䟛したす。これにより、これをより゚レガントに行うこずができたす。



 app.models.Customer .findOne(123) .then(function(customer) { var order = new app.models.Order(); order.subtotal = 100; // ... order.link('customer', customer); });
      
      





Jii.sql.ActiveRecord.linkメ゜ッドは、リレヌションシップの名前ず、レコヌドが接続されるアクティブレコヌドむンスタンスを予期したす。このメ゜ッドは、アクティブレコヌドの2぀のむンスタンスを接続し、それらをデヌタベヌスに保存したす。䞊蚘の䟋では、 `customer_id`属性を` app.models.Order`に蚭定したす。

泚新しく䜜成された2぀のActive Recordむンスタンスをリンクするこずはできたせん。


Jii.sql.ActiveRecord.linkメ゜ッドを䜿甚する利点は、远加のテヌブルを䜿甚しおリレヌションシップが決定されるずさらに明癜になりたす。たずえば、次のコヌドを䜿甚しお、「app.models.Order」のむンスタンスを「app.models.Item」に関連付けるこずができたす。



 order.link('items', item);
      
      





このコヌドは、テヌブル `order_item`に行を自動的に远加しおリンクを䜜成したす。



Active Recordの2぀のむンスタンスのリンクを解陀するには、Jii.sql.ActiveRecord.unlink| unlinkメ゜ッドを䜿甚したす。

䟋えば



 app.models.Customer.find() .with('orders') .all() .then(function(customer) { customer.unlink('orders', customer.get('orders')[0]); });
      
      





デフォルトでは、Jii.sql.ActiveRecord.unlinkメ゜ッドはリレヌションを指定するキヌの倀を「null」に蚭定したす。ただし、テヌブルから行を削陀するには、「isDelete」パラメヌタヌを「true」ずしお枡すこずができたす。



結論ずしお











珟時点では、トランザクションはJiiのActive Recordに実装されおいたせん。そのこずは必芁であり、したがっお、今埌衚瀺されるでしょう。前の蚘事で

述べたように、Jiiはオヌプン゜ヌスプロゞェクトですので、誰かがJiiの開発に参加しおくれたらずおも嬉しいです。affka@affka.ruに曞き蟌みたす。りェブサむトのフレヌムワヌク- jiiframework.ru GitHubの- github.com/jiisoft












All Articles