doubaoxue5788 2011-05-01 20:51
浏览 23
已采纳

使用ORM创建嵌套关系并最小化查询

Edit 3

After reading a boat load I really don't think with any ORM or system in general it is possible to build the relationships of organized objects like I want in fewer queries that I am using. If any can provide an example of it being possible I would kiss you.

In Edit 2 The nested for loops I think is the best solution running

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

I would love a better example because to populate simple projects I would probably be running 200-500 queries. This is bad.

Edit 2

Well I have been playing with this for a while now and I have some results but I do not think they are the "RIGHT" way and that matters to me a lot. What I do is I use the where_related method to get the right objects but I think my query count is still pretty high and I know an ORM can do better. When I use the where related to create the proper hierarchy I have to use nested foreach loops and I don't like that. That means useless querying.

Here is the solution I came up with

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 outputs a nice tiered structure and as you can see it would be easy to replace the echos with object/array population.

What I would rather have though is one chained command that did the same thing if possible that way scoping isn't an issue either.

Some chain more resembling

$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()

That of course does not achieve anywhere near the same results as the nested foreach loops but what I would like to know is it possible to chain relationships and populate objects without nested foreach

So I just did some profiling and the nested foreach loops generate 63 queries on a small project, and take almost half a second to generate results. This is really too slow. There must be a better query.

__________Edit 1

All the below information is great but I have been playing with it and I cannot seem to get any relationship to work let alone a 3 tiered one. I have tried just about everything I can think of and read the doc's but for somereason my brain doesn't like the ORM.

I would like to just echo the id's of all slides in a project. I will give a list of what I have tried with no avail. My model structure is the same as below I am just adding methodes.

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();
    }

}

And I have tried what I would think is the logical opposite in the Slide Method.

What am I doing wrong... How do you structure ORM relationships?


Original Question

I am using an ORM for the first time and I am having huge problems visualizing how to structure the code to pull data from the relationships.

I am using DataMapper as my ORM with CodeIgniter. I have the installation working just fine and I read all the docs, I just cannot get my head around how to get information in controllers

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

Models -

project.php

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

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

slide.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 

The above should create a decending one->many relationship between projects->slides->shapes->points

How do you start to deal with information? When I was not using an ORM I handled all data processing in the Model is this incorrect for the ORM Models? Say you wanted to get all the points in all the shapes in project 1 how would you go about structuring such a call?

I don't really need specific code if you want that would be helpful. What I really need is some ideas on how to visualize how to tier the objects so you can deal with each at any tier.

  • 写回答

6条回答 默认 最新

  • drwurqczo39355510 2011-05-01 21:56
    关注

    First of all, I'm sorry to break this to you , but CodeIgniter's DataMapper is actually a variation of ActiveRecord pattern.

    If you care, you compare the real DataMapper pattern with its counterpart - ActiveRecord. In short - difference is in fact that in DM pattern you Domain Object is unaware of type ( and even the existence ) of storage. It is used in manner like $mapper->store( $user );.

    "Favor object composition over class inheritance." © GoF

    That said..


    If i read the examples right then it should work like this: ( i am assuming that relationships between 'entities' are already established )

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

    Then you can use something like

    $project = new Project;
    $all_points = $project->where( 'id' , 1 )->get_all_points();
    
    foreach ( $all_points as $point )
    {
       $point->x = 0;
       $point->save();
    }
    

    This should gather all th points that are related to project with ID 1, and set the X value to 0 and store each in the database .. not that any sane person would do it.



    I am not using any sort of ORM, that's why i really hope i got this wrong, because this looks to me like an abomination.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(5条)

报告相同问题?

悬赏问题

  • ¥15 PointNet++的onnx模型只能使用一次
  • ¥20 西南科技大学数字信号处理
  • ¥15 有两个非常“自以为是”烦人的问题急期待大家解决!
  • ¥30 STM32 INMP441无法读取数据
  • ¥15 R语言绘制密度图,一个密度曲线内fill不同颜色如何实现
  • ¥100 求汇川机器人IRCB300控制器和示教器同版本升级固件文件升级包
  • ¥15 用visualstudio2022创建vue项目后无法启动
  • ¥15 x趋于0时tanx-sinx极限可以拆开算吗
  • ¥500 把面具戴到人脸上,请大家贡献智慧,别用大模型回答,大模型的答案没啥用
  • ¥15 任意一个散点图自己下载其js脚本文件并做成独立的案例页面,不要作在线的,要离线状态。