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>";
            }
        }
    }
}

这会输出一个很好的分层结构,如您所见,用对象/数组填充替换回声很容易。

我宁愿拥有一个链式命令,如果可能的话,它会做同样的事情,这样范围界定也不是问题。

一些链条更像

$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 个查询,并且需要将近半秒的时间来生成结果。这实在是太慢了。一定有更好的查询。

__________编辑 1

以下所有信息都很棒,但我一直在玩它,我似乎无法建立任何关系,更不用说 3 层了。我已经尝试了我能想到的所有内容并阅读了文档,但出于某种原因,我的大脑不喜欢 ORM。

我只想slides在一个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,在可视化如何构建代码以从关系中提取数据时遇到了巨大的问题。

我使用DataMapper作为我的 ORM 和CodeIgniter。我的安装工作正常,我阅读了所有文档,但我无法理解如何在控制器中获取信息

+-----------+    +------------+    +---------+    +----------+
|  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 

形状.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 

点.php

<?php

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

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

以上应该在项目->幻灯片->形状->点之间创建一个递减的一>多关系

你如何开始处理信息?当我不使用 ORM 时,我在模型中处理了所有数据处理,这对于 ORM 模型是否不正确?假设您想获得项目 1 中所有形状的所有点,您将如何构建这样的调用?

如果您愿意,我真的不需要特定的代码会有所帮助。我真正需要的是一些关于如何可视化如何分层对象的想法,以便您可以在任何层处理每个对象。

4

6 回答 6

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 的项目相关的所有点,并将 X 值设置为 0 并将每个点存储在数据库中......不是任何理智的人都会这样做。



我没有使用任何类型的 ORM,这就是为什么我真的希望我弄错了,因为这在我看来是可憎的。

于 2011-05-01T21:56:51.767 回答
0

我不确定 Datamapper 是如何做到的,但我有一个用于 Codeigniter 的自定义 GenericObject 模型,它像这样执行 ORM:

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

对于大多数关系数据,我通常会在需要时延迟加载对象。我不是 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

首先:我对 CI 自己的 ORM 实现一无所知,但是当我看到你在做什么时,要么它缺少某些功能,要么你以错误的方式使用它(来自你的编辑#2)。

然而,在Propel中(只是提到这一点,因为这是我最常使用的,Doctrine是另一个不错的选择)这些事情很容易完成,尤其是在新的 1.6 分支中,使用流畅的接口。只需查看有关关系的文档即可。这看起来不像你想要使用的东西吗?:p

于 2011-05-02T08:07:45.063 回答
0

据我了解,考虑到每个表之间的约束,您希望检索一个具有所有关联点的项目。

检查这个 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

看看格拉纳达

从自述文件:

class User extends Model {
         public static $_table = 'user';

         public function post(){
               return $this->has_many('Post');
         }
         public function avatar(){
               return $this->has_one('Avatar');
         }
   }

您可以在您的关系中包含关系!

$user_list = Model::factory('User')->with(array('post'=>array('with'=>'comments')),'avatar')->find_many();

它将进行 3 个查询:

SELECT * FROM user 
SELECT * FROM avatar WHERE user.id IN (......)
SELECT * FROM post WHERE user.id IN (.....)
于 2013-02-13T14:01:06.690 回答