3

編集 3

ボートロードを読んだ後、一般的に、ORMやシステムでは、使用しているクエリの数を減らして、組織化されたオブジェクトの関係を構築できるとは本当に思いません。それが可能であるという例を提供できる人がいるなら、私はあなたにキスします.

編集 2ネストされた for ループは、実行中の最良のソリューションだと思います

Total_queries = 1 + 2(Slides_in_project) + Shapes_in_project
                |                |                        \
  Query to get project           |                         \
                                 |                          \
        Query to get slides and double because of points     \
                                                              \
                                              Get all the shapes in the project

単純なプロジェクトにデータを入力するには、おそらく 200 ~ 500 のクエリを実行することになるため、より良い例が欲しいと思います。これは悪いです。

編集 2

さて、私はこれでしばらく遊んでいて、いくつかの結果が得られていますが、それらが「正しい」方法であるとは思いません。それは私にとって非常に重要です. 私がしていることは、where_relatedメソッドを使用して適切なオブジェクトを取得することですが、クエリ数はまだかなり多いと思います.ORMの方がうまくいくことがわかっています. where 関連を使用して適切な階層を作成する場合、ネストされたforeachループを使用する必要があり、それが気に入りません。つまり、無駄なクエリです。

これが私が思いついた解決策です

function get_project_points($link_id)
{
    echo "<pre>";
    foreach($this->where('link_id', $link_id)->get()->slide->where_related('project', 'id', $this)->get() as $slide){
        echo $slide->id."<br>";
        foreach($slide->shape->where_related('slide', 'id', $slide->id)->get() as $shape){
            echo "\t".$shape->id."<br>";
            foreach ($shape->point->where_related('shape', 'id', $shape->id)->get() as $point) {
                echo "\t\t".$point->id."<br>";
            }
        }
    }
}

これにより、適切な階層構造が出力されます。ご覧のとおり、エコーをオブジェクト/配列の人口に置き換えるのは簡単です。

私がむしろ持っているのは、可能であれば同じことを行う1つの連鎖コマンドであり、スコープも問題ではありません。

より似ているいくつかのチェーン

$this->where('link_id', $link_id)->get()
    ->slide->where_related('project', 'id', $this)->get()
    ->shape->where_related('slide', 'id', $slide->id)->get()
    ->point->where_related('shape', 'id', $shape->id)->get()

もちろん、ネストされた foreach ループと同じ結果に近い結果は得られませんが、知りたいのは、関係を連鎖させ、ネストされた foreach なしでオブジェクトを設定できることです。

そのため、プロファイリングを行ったところ、ネストされた foreach ループが小さなプロジェクトで 63 のクエリを生成し、結果を生成するのにほぼ 0.5 秒かかりました。これは本当に遅すぎます。より良いクエリが必要です。

__________編集 1

以下の情報はすべて素晴らしいですが、私はそれで遊んでいて、3 層の関係はもちろんのこと、関係がうまくいかないようです。私は考えてドキュメントを読むことができるほとんどすべてを試しましたが、何らかの理由で私の脳はORMが好きではありません.

slidesのすべてのIDをエコーし​​たいだけprojectです。私が無駄に試したことのリストを提供します。私のモデル構造は以下と同じです。メソッドを追加しているだけです。

class Project extends DataMapper {
    var $has_many = array("slide");

    function get_project_slides($link_id)
    {
        $this->where('link_id', $link_id)
            ->where_related('slides', 'project_id' 
                $this->where('link_id', $link_id)->get()->id
            )
        ->get();
    }

}

そして、スライド法で論理的に反対だと思うことを試してみました.

何が間違っているのですか... ORM関係をどのように構築していますか?


元の質問

初めて ORM を使用していますが、コードを構造化して関係からデータを取得する方法を視覚化するのに大きな問題があります。

CodeIgniterで ORM としてDataMapperを使用しています。インストールは問題なく機能しており、すべてのドキュメントを読みましたが、コントローラーで情報を取得する方法がわかりません

+-----------+    +------------+    +---------+    +----------+
|  projects |    | slides     |    | shapes  |    |  points  |
+-----------+    +------------+    +---------+    +----------+
|    id     |    |  id        |    | id      |    | id       |
+-----------+    | project_id |    |slide_id |    | shape_id |
                 +------------+    +---------+    | x        |
                                                  | y        |
                                                  +----------+

モデル -

プロジェクト.php

class Project extends DataMapper {
    var $has_many = array("slide");
}

//  End of project.php
//  Location: ./application/models/project.php 

スライド.php

<?php

class Slide extends DataMapper {
    var $has_many = array("shape");
    var $has_one = array("project");
}

//  End of slide.php
//  Location: ./application/models/slide.php 

shape.php

<?php

class Shape extends DataMapper {
    var $has_many = array("point");
    var $has_one = array("slide");
}

//  End of shape.php
//  Location: ./application/models/shape.php 

point.php

<?php

class Point extends DataMapper {
    var $has_one = array("shape");
}

//  End of point.php
//  Location: ./application/models/point.php 

上記は、プロジェクト - >スライド - >シェイプ - >ポイント間に下降する1->多関係を作成する必要があります

情報をどのように扱い始めますか?ORM を使用していないときは、モデルですべてのデータ処理を処理しましたが、これは ORM モデルでは正しくありませんか? プロジェクト 1 のすべての形状のすべてのポイントを取得したいとします。そのような呼び出しをどのように構造化しますか?

必要に応じて、特定のコードは必要ありません。私が本当に必要としているのは、オブジェクトを階層化する方法を視覚化して、任意の階層でそれぞれを処理できるようにする方法についてのアイデアです。

4

6 に答える 6

0

Datamapperがどのようにそれを行うかはわかりませんが、次のようなORMを行うCodeigniter用のカスタムGenericObjectモデルがあります。

class Article extends GenericObject
{
    public $relationships = array ( "has_many" => array ("comments"), "has_one" => array ("users") );
}
class Comments extends GenericObject
{
    public $relationships = array ( "belongs_to" => array ("articles", "users"), "has_one" => array ("users") );
}
class Users extends GenericObject
{
    public $relationships = array ( "has_many" => array ("comments", "articles") );
}

ユーザーからすべてを取得したい場合は、次のようにすることができます。

$User = new User( $some_user_id );
$User->boot_relations("all");

foreach ($User->Comments as $Comment)
{
    echo $Comment->title."<br />";
    echo $Comment->body."<br />";
    echo "written by ".$User->username;
}

したがって、かなりエレガントにすることができます(または少なくとも私はそう思うのが好きです)。

于 2011-05-01T22:11:00.393 に答える
0

まず最初に、これを壊して申し訳ありませんが、CodeIgniter の DataMapper は実際には ActiveRecord パターンのバリエーションです。

気にするなら、実際のDataMapperパターンを対応するActiveRecordと比較します。要するに、実際の違いは、DM パターンではドメイン オブジェクトがストレージのタイプ (さらには存在) を認識しないことです。のような使い方$mapper->store( $user );です。

「クラスの継承よりもオブジェクトの構成を優先します。」© GoF

そうは言っても..


例を正しく読めば、次のように動作するはずです: (「エンティティ」間の関係はすでに確立されていると想定しています)

class Project extends DataMapper
{
   // --- the rest of your stuff 

   public function get_all_points()
   {
      $points = array();

      $slides = $this->slide->get()->all;


      foreach ( $slides as $slide )
      {
         $shapes = $slide->shape->get()->all;

         foreach ( $shapes as $shape )
         {
            $points = array_merge( $point = $shape->point->get();
         }
      }

      return $points;

   }


}

次に、次のようなものを使用できます

$project = new Project;
$all_points = $project->where( 'id' , 1 )->get_all_points();

foreach ( $all_points as $point )
{
   $point->x = 0;
   $point->save();
}

これにより、ID 1 のプロジェクトに関連するすべての th ポイント収集され、X 値が 0 に設定され、それぞれがデータベースに保存されます。



私はいかなる種類の ORM も使用していません。そのため、これが間違っていることを本当に望んでいます。

于 2011-05-01T21:56:51.767 に答える
0

ほとんどのリレーショナル データでは、通常、必要なときにオブジェクトを遅延読み込みします。私は PHP 開発者ではありませんが、疑似コードで行うことは次のとおりです。

class Projects {
    var slides = null;
    function getSlides() {
        if(slides == null) {
            slides = getSlidesForProject(this.id);
        }
        return slides;
    }
}

class Slides {
    var shapes = null;
    function getShapes() {
        if(shapes == null) {
            shapes = getShapesForSlide(this.id);
        }
        return slides;
    }
}

class Shapes {
    //... same as Projects.getSlides and Slides.getShapes
}

残念ながら、プロジェクトのすべてのポイントを取得する必要がある場合、これによりデータベースへの複数の呼び出しが発生します。

どの MVC ソリューションでも、軽いコントローラーと重いモデルを使用して、コードの再利用とテストを容易にすることをお勧めします。

于 2011-05-01T22:50:04.537 に答える
0

私が理解していることから、各テーブル間の制約を考慮して、関連するすべてのポイントを含む 1 つのプロジェクトを取得したいと考えています。

この sqlFiddle を確認してください: http://sqlfiddle.com/#!2/9ed46/2

スキーマ作成:

CREATE TABLE project
    (
     id int auto_increment primary key, 
     name varchar(20)
    );

CREATE TABLE slide
    (
     id int auto_increment primary key, 
     name varchar(20),
     project_id int
    );

CREATE TABLE shape
    (
     id int auto_increment primary key, 
     name varchar(20),
     slide_id int
    );


CREATE TABLE point
    (
     id int auto_increment primary key, 
     name varchar(20),
     shape_id int
    );

リクエスト:

select project.id as project_id, project.name as project_name,
       slide.id as   slide_id,   slide.name as   slide_name,
       shape.id as   shape_id,   shape.name as   shape_name,
       point.id as   point_id,   point.name as   point_name

from project

left join slide on slide.project_id = project.id
left join shape on shape.slide_id   = slide.id
left join point on point.shape_id   = shape.id

where project.id = 1

次のようなものが返されます。

PROJECT_ID PROJECT_NAME SLIDE_ID SLIDE_NAME SHAPE_ID SHAPE_NAME POINT_ID POINT_NAME
1          fst_project  1       fst_slide   1        fst_shape  1        first_pt
1          fst_project  1       fst_slide   1        fst_shape  2        2nd_pt
...

この出力を処理することで、必要なオブジェクト ツリーを構築できます。すべてを 1 つのクエリで実行できます。ただし、この後処理には時間がかかる場合があります。各ポイントをループする必要があります。

于 2013-02-13T10:26:46.817 に答える
0

最初に:CI独自のORM実装については何も知りませんが、あなたが何をしているのかを見ると、いくつかの機能が欠けているか、間違った方法で使用しています(編集#2から)。

しかし、Propelでは ( Doctrineが別の良い代替手段である場合、私が最もよく使用するものであるため、これについて言及します)、特に新しい 1.6 ブランチでは、流暢なインターフェースを使用して、これらのことを簡単に行うことができます。Relationshipsのドキュメントを参照してください。それはあなたが使いたいもののように見えませんか?:p

于 2011-05-02T08:07:45.063 に答える