Home / PostsPost

CodeIgniter Doctrine2基本使用(三)

嘟噜聪2015/07/11 18:17:25 4369人已阅

简介 本章主要介绍对象之间的关联映射,引用一个单一目的通过一种外键进行表示。哎呀,看官方的解释越看越是不懂,我就用简单的语言描述一下吧,本章主要讲的就是一对多,多对一,一对一及多对多的关系。我觉得每一个关系都可以单独拿出来写一篇文章了...

CodeIgniter Doctrine2基本使用(三)

本章主要介绍对象之间的关联映射,引用一个单一目的通过一种外键进行表示。哎呀,看官方的解释越看越是不懂,我就用简单的语言描述一下吧,本章主要讲的就是一对多,多对一,一对一及多对多的关系。我觉得每一个关系都可以单独拿出来写一篇文章了...

Doctrine2 用法

操作实体

如果对本间不是很明确的可以点击上面两个连接分别对CodeIgniter Doctrine2进行了相关介绍,建议先从第一章开始看,如果跳过前面两章的话可能会看不懂这章哦,当然如果您对Doctrine2本来就非常了解的话请随意...

ManyToOne 基本

呃,先从简单的多对一关系开始讲吧...ManyToOne就是查询的主表里有多条数据,而关联的表里的那个ID是唯一的,也就是One的那个表ID是唯一的而在Many表里所关联的那个ID可以存在多个...哎呀,越说越不明白了,下面直接通过一个例请解吧,简单明了绝对好理解...

因为是关联映射所以这里我们需要新增加一个实体对象,这里我们就用Entity\User这个实体好了,每个用户只能属于一个渠道,也就相当于组的关系吧(这样会好理解一下),那这时有人就会问了:"哎,你怎么不用Entity\Group来讲解啊",这里我想说的是,我不用Entity\Group是因为有一些包括官方也是用Group来写例子的,我不想大家说我是抄袭啊什么的...(原创就是原创,本人原创的文章全部都是手写的,绝无复杂粘贴)。OK下面咱们来看Entity\User这个实体...

namespace Entity;

/**
 * User
 *
 * @Table(name="user", uniqueConstraints={@UniqueConstraint(name="email", columns={"email"})}, indexes={@Index(name="user", columns={"email"})}, @Index(name="channel", columns={"channelId"}))
 * @Entity
 */
class User
{
	/**
     * @var integer
     *
     * @Column(name="userId", type="integer", precision=0, scale=0, nullable=false, unique=false)
     * @Id
     * @GeneratedValue(strategy="IDENTITY")
     */
    private $userId;
    
    /**
     * @var string
     *
     * @Column(name="email", type="string", length=32, precision=0, scale=0, nullable=false, unique=true, options={"comment": "邮箱"})
     */
    private $email;
    
    /**
     * @var string
     *
     * @Column(name="password", type="string", length=128, nullable=false, unique=false, options={"comment": "密码,hash256"})
     */
    private $password;
    
    /**
     * @var integer
     *
     * @Column(name="channelId", type="integer", nullable=false, unique=false, options={"comment": "关联的渠道ID"})
     */
    private $channeId;
    
    /**
     * @var string
     *
     * @Column(name="createAt", type="datetime", nullable=false, unique=false, options={"comment": "创建时间"})
     */
    private $createdAt;
    
    /**
     * @var \Entity\Channel
     *
     * @ManyToOne(targetEntity="Entity\Channel")
     * @JoinColumn(name="channelId", referencedColumnName="channel_id", nullable=true)
     */
    private $channelInfo;
    
    public function __construct()
    {
    	$this->createdAt(new \DateTime());
    }
}

先对上面的几个参数进行一个简单的解释吧

  • @ManyToOne() 说明这个成员是一个多对一的关系
    • targetEntity 这个参数设置所映射的实体对象
  • @JoinColumn() 关联的字段
    • name 本实体的字段名,注意不是成员属性名称而是字段名
    • referencedColumnName 对应实体的字段名称,也就是关联的ID
    • nullable 是否没空,我好像一直设置的都是可以为空,好像也并没有什么卵用...可能是我现在还没有用到吧...

OK基本的信息已经都写好了,咱们在./app/目录下执行一下命令: php doctrine orm:generate:entities ./models/ --update-entities="true" --generate-methods="true" 然后它会生成相应的方法,前面的我就不多作解释了如有不清楚的欢迎查看《CodeIgniter Doctrine2基本使用(一)》这篇文章,里边对这几个常用的命令有相应的解释,如果想知道更多的命令的话可以查看《CodeIgniter 3.0整合Doctrine2》这篇文章的后半部分(好像也没写啥...等有时间我再一一介绍吧...)这里我就只介绍新生成的 setChannelInfo()getChannelInfo()方法了...

	/**
     * Set channelInfo
     *
     * @param \Entity\Channel $channelInfo
     *
     * @return User
     */
    public function setChannelInfo(\Entity\Channel $channelInfo = null)
    {
        $this->channelInfo = $channelInfo;

        return $this;
    }

    /**
     * Get channelInfo
     *
     * @return \Entity\Channel
     */
    public function getChannelInfo()
    {
        return $this->channelInfo;
    }

如上面代码我们所看到了,这两个方法与其他方法有一点点的不一样,特别是这个setChannelInfo() 方法,里面传的不是一个字符串什么的,而是一个对象,也就是说我们必须传一个对象进来。当然我们上面定义了nullable=true这个为空,也就是说可以不传这个过来,但是真的吗?不一定...至少在我看来是这样,因为它设置了外键,不信的话咱们使用命令php doctrine orm:schema-tool:create --dump-sql 查看它所生成的语句,它会对*user*表设置一个关联外键,也就是说它不能为空... 好了下面我就用一个简单的例子来说明吧...

ManyToOne 插入一条记录

当然先从简单的插入数据开始啦,不为什么,就是简单而已...不多说了,直接上代码吧...

$channel = $this->em->getRepository('Entity\Channel');

$channelInfo = $channel->find(1);

$user = new \Entity\User();

$user->setEmail( 'latte@latteCake.com' )
	->setPassword( hash('sha256', '111111') )
	->setChannelInfo( $channelInfo );
	
$this->em->persist( $user );
$this->em->flush();

如上面代码,保证能插入成功,很多人会觉得奇怪为什么不设置setChannelId()这个成员呢?其实嘛以前我也是这样设置的,可以后来回ManyToOne的关系后发现,每次set它就报错,说这个参数不能为空什么的,老恶心了,直到后来才发现我必须要把Entity\Channel这个实体塞进去才行,不需要设置那个关联ID程序会自动进行关联设置,所以我再去设置*channelId*的话就显示有些多余了。它具体是怎么做到的,本人不才,没有深入去了解过,反正很复杂啦,想想就复杂...如果不知道它生成的语句可以用上面说到的命令打印语句出来看看。

ManyToOne 关联查询

查询那就更简单啦,几乎什么都不用做,如果需要用它渠道信息的时候使用getChannelInfo()这个方法就行了,它会返回Entity\Channel这个实体对象,还是那句话讲辣么多还不如直接定一段代码延时来得好理解。

$user = $this->getRepository('Entity\User');

/** @var $userInfo \Entity\User */
$userInfo = $user->findOneBy(['email' => 'latte@latteCake.com']);

echo $userInfo->getEmail();		// 打印邮箱

echo $userInfo->getChannelInfo()->getChannelName();  // 打印渠道名称

var_dump( $userInfo );
var_dump( $userInfo->getChannelInfo() );

如上面代码所展示的那样,如果Entity\Channel这个实体也设置了关联对象的话,那么可以一直这样get下去,不过不推荐这样使用,经过我的试验发现它是生成的left Join {table}这样的语句,其实效率并不是很高,当然如果数据量大的话也不推荐这样使用,还是拆开多条语句分别查询再进行数合,这样的话虽然查询次数增多了,但关联的表数量减少了,天理论上消耗的数据库资源是更少的,也就是说查询的速度将会更快一些。

我看到一些书,或文章是这样写的,如果不使用getChannelInfo()这个方法的话理论上是不会去关联查询另一张表的数据的,然后经过我的多次试验,发现好像并不是这样,难道是我的使用方式不对?可是我看到*laravel*上面使用的ORM是生成的where in 条件语句,就像我上面说的那样,拆开多条语句进行查询,然后再进行组合,最终成咱们平时使用的样纸,我觉得应该也是这样才对,一定是我使用的方式不对,一定是。不过我使用的ManyToMany好像生成的语句是where in呃... 具体的我还得再研究研究...

对了这里忘记说了,当第一次运行该方法的时候会在./app/models/Proxies目录生成几个类型__GC__EntityChannel.php 这样的文件,具体的看《CodeIgniter 3.0整合Doctrine2》这篇文章是设置,可以打开这个文件看看(说实话...看不太懂(・・;)),里面设置的 Proxies 目录如果使用的缓存的话还会生成文件吗,好像也会。回头我去试试看?

OneToMany

其实OneToManyManyToOne是差不多的,就是对应关系不一样而已 *OneyToMany*就如字面上的意思那样,一对多的关系,这个咱们也比较常用,比如还是以渠道和用户的关系来查询,这次咱们查询条件是查询出该渠道的所有用户,这个看咱们怎么通过 ORM 来实现吧。还是上面那句话,用代码来解释更直观。

首先先在Entity\Channel这个实体增加一个users属性。

	// \Entity\Channel
	/**
     * @var \Entity\User
     *
     * @OneToMany(targetEntity="Entity\User", mappedBy="channelInfo", cascade={"all"}, fetch="EAGER", orphanRemoval=true)
     */
     private $users;

然后咱们还再需要修改一下Entity\User这个实体的的channelInfo属性。注意,这里我们新增加了一个参数inversedBy值就是对应的Entity\Channel实体的users这个成员,其他的的不变。

	// \Entity\User
	/**
     * @var \Entity\Channel
     *
     * @ManyToOne(targetEntity="Entity\Channel", inversedBy="users")
     * @JoinColumn(name="channelId", referencedColumnName="channel_id", nullable=true)
     */

设置好上面相关参数后咱们再执行一下命令php doctrine orm:generate:entities ./models/ --update-entities="true" --generate-methods="true" 然后就可以使用了,来我们写一短代码试试看。

$channel = $this->em->getRepository('Entity\Channel');

/** @var $channelInfo \Entity\Channel */
$channelInfo = $channel->find(1);

echo $channelInfo->getChannelName();

/** @var $user \Entity\User */
foreac( $channelInfo->getUsers() as $user )
{
	echo $user->getEmail();
}

var_dump( $channelInfo->getUsers() );

哈哈,系不系很简单哇,哈哈哈哈哈哈,不信的话可以打印一下结果看看。虽然这些代码是我直接在Markdown上写的没有经过测试,可我还是相当自信它能输出我想要的东西的...

就是这么自信

好了,今天就先写到这里吧,下篇文章我将讲解ManyToManyOneToOne,真是越来越熟练了呢...写得不好还请多多指点指点。

(ps: print_r() or var_dump() 打印实体慎用,建议装 xdebug 插件,浏览器挂了憋找我...)

很赞哦! (3)

文章评论

点击排行

本栏推荐

标签

站点信息

  • 微信公众号