您的位置:澳门402永利com > 编程应用 > Doctrine2基本使用

Doctrine2基本使用

发布时间:2019-09-23 20:45编辑:编程应用浏览(85)

    CodeIgniter Doctrine2基本使用

    继上次写的一篇文章《CodeIgniter Doctrine2基本使用》写到操作实体的之通过Channel这个实体向数据库表插入一条数据,那么今天要写的就是通过实体获取数据,当然查询这一块比较多,可能也会分好几篇讲。

    CodeIgniter Doctrine2基本使用

    之前写了一篇文章叫作《CodeIgniter 3.0整合Doctrine2》里面介绍了一些简单的Doctrine2的用法,当然我也已经把它运用到项目上去了。下面我就写一些Doctrine2在CodeIgniter框架上的一些使用及感受吧...

    在项目上运用了一段时间后发现,好像代码比格变高了呃,连同事都说你这种写法好像很高级的样纸呃,并且代码特别好看。虽然现在运用的广度还不是很大,但逐渐的我会把它给运动到所有模块上去,现新功能或新模块都使用了Doctrine ORM结构。新的结构确实可以少写很多代码,虽然运行的效率并不怎么高,不过总会有办法解决的。下面我将对一些我用过或现在正在用的一些东西进行一些简单的讲街,本人文采烂,能力有限看不明白也请谅解谅解...

    Doctrine2 简单的用法

    Doctrine2 简单的用法

    操作实体

    • 《CodeIgniter 3.0整合Doctrine2》
    • 《CodeIgniter Doctrine2基本使用》

    上一篇文章讲到插入一条数据,插入很简单只要设置实体的成员属性的值就能完成,当然如果有多个实体的话可以多次使用$this->em->persist();这个方法。然后只要再执行一次$this->em->flush();这个方法就行了,它会进行一次数据库连接,然后执行上面实体生成的SQL语句。

    创建一个实体 Entity

    比如我们现在需要一个渠道channel的数据表,表里面有很多字段那我在model/Entity目录创建一个Channel.php的文件

    // Channel.php 部分代码namespace Entity;use EntityRepositoryChannelRepository;/** * Channel * * @Table(name="channel", options={"collate"="utf8_general_ci","charset"="utf8"}, uniqueConstraints={@UniqueConstraint(name="channel_code", columns={"channel_code"})}) * @Entity(repositoryClass="EntityRepositoryChannelRepository") */ class Channel {  /**     * @var integer     *     * @Column(name="channel_id", type="integer", nullable=false, options={"comment": "渠道id"})     * @Id     * @GeneratedValue(strategy="NONE")     */    private $channelId;    /**     * @var integer     *     * @Column(name="channel_tag", type="integer", nullable=false, options={"comment": "渠道标识"})     * @Id     * @GeneratedValue(strategy="NONE")     */    private $channelTag;    /**     * @var string     *     * @Column(name="channel_name", type="string", length=128, nullable=false, options={"comment": "渠道名称"})     */    private $channelName;        /**     * @var string     *     * @Column(name="channel_time", type="datetime", nullable=false, options={"comment": "渠道创建时间"})     */    private $channelTime;        public function __construct()    {    $this->channelTime = new DateTime;    } }
    

    OK 先写三个字段吧,然后我们进入./app目录执行php doctrine命令会显示一些doctrine可以使用的一些命令,然后我们现在要创建每个字段的 getter 和 setter 方法,所以我们执行命令

    php doctrine orm:generate:entities ./models/ --update-entities="true" --generate-methods="true"

    当然可以执行php doctrine orm:generate:entities --help查看 orm:generate:entities 的用法;--update-entities="true"表示需要更新实体--generate-methods="true"表示更新或生成每个成员属性的 getter 和 setter 方法(我猜的,因为之前不生成方法时我找了好长时间才知道是怎么回事),对了这里还写了一个构造函数,缺省设置了一个时间,当 new Channnel()的时候就不再需要set这个时间字断了

    生成功能后Channel这个实体应该会多出7个方法:

    /**     * Get channelId     *     * @return integer     */    public function getChannelId()    {        return $this->channelId;    }    /**     * Set channelTag     *     * @param integer $channelTag     *     * @return Channel     */    public function setChannelTag($channelTag)    {        $this->channelTag = $channelTag;        return $this;    }    /**     * Get channelTag     *     * @return integer     */    public function getChannelTag()    {        return $this->channelTag;    }    /**     * Set channelName     *     * @param string $channelName     *     * @return Channel     */    public function setChannelName($channelName)    {        $this->channelName = $channelName;        return $this;    }    /**     * Get channelName     *     * @return string     */    public function getChannelName()    {        return $this->channelName;    }/**     * Set channelTime     *     * @param DateTime $channelTime     *     * @return Detail     */    public function setCreateTime($channelTime)    {        $this->channelTime = $channelTime;        return $this;    }    /**     * Get channelTime     *     * @return DateTime     */    public function getChannelTime()    {        return $this->channelTime;    }
    

    getter 是获取这个字段的值,setter 是设置该字段的值,咱们回到上面的成员属性看比如:

    /**     * @var string     *     * @Column(name="channel_name", type="string", length=128, nullable=false, options={"comment": "渠道名称"})     */    private $channelName;
    

    注释里有@var string这个表示它返回的会是什么,这不重要,重要的看下面这个@Column这个很重要,是必须设置的;括号里边就是对这个成员属性的相关设置也就是这个字段的属性。

    • name: 表字段名
    • type: 表字段类型(string,integer,datetime,text,bigint等等)
    • length: 表字段长度
    • nullable: 是否为空(true or false)
    • unique: 是否唯一(true or false)
    • precision: (暂时不知道是干啥的只设置过0)
    • scale: (与上个字段一样为0吧)
    • options: 这里可以设置很多东西,我好像只设置过 commint 跟 default 这两个参数

    OK明白上面的东西后我们就生成SQL语句吧执行命令php doctrine orm:schema-tool:create --dump-sql生成建表语句,如果想直接创建表的话把后面的参数--dump-sql去掉就行了;php doctrine orm:schema-tool:update --dump-sql这条命令与上面生成SQL语句的命令一样这是打印出有更新的字段如果不想打印把后面的参数--dump-sql去掉就直接更新数据库表了;

    这样我们表就建好了;

    简单查询操作

    通过Entity查询的方式 有很多,我们先从最简单的开始,还是以EntityChannel这个实体为例,以下面一段代码为例:

    public function index(){$id = 1;$limit  = 20;$offset = 1;/** * @var  $channelInfo EntityChannel * @var  $channelOneBy EntityChannel */ $channelRepository = $this->em->getRepository('EntityChannel');$channelAll  = $channelRepository->findAll();$channelInfo = $channelRepository->find;$channelOneBy = $channelRepository->findOneBy(['channelName' => '百度'], ['channelId' => 'DESC']);$channelBy= $channelRepository->findBy(['channelName' => '阿里'], ['channelId' => 'DESC'], $limit, $offset);/** @var $value EntityChannel */foreach( $channelBy as $value ){echo $value->getChannelName();}echo $channelInfo->getChannelName();var_dumt( $channelInfo );}
    

    看上面一段代码,分别写了4个咱们比较常用的并且简单的查询方式,下面对这些方法进行一个简单的解释:

    • findAll这个方法表示查询这个实体的所有数据,也就是查询相应表的所有数据,它返回的是一个多维数组 对象,可以通过foreach进行遍历。
    • find这个是按照ID查询数据,返回一条结果,也就是一个Channel实体对象。
    • findOneBy这个是根据条件查询一条数据,可传入两个数组参数,第一个参数是简单的查询数组,可以写多个它们是AND的关系。第二个参数是排序,上面我是channelId这个字段排序。
    • findBy这个与上面那个findOneBy方法类似,前两个参数都一样,第三个参数表示查询的数量,第四表参数表示从第几行开始,返回的是多维数组对象,可以用foreach遍历。

    为什么我要写/** @var $value EntityChannel */这样的一些注释? 关于这点,我上篇文章已经讲过了一些,可远远不只是那样。这样写表示$value这个变量它指向了实体对象EntityChannel,因为查询到结果后把结果设置到EntityChannel这个实体上并且返回这个实体。然后咱们就可以使用这个实体里的一些方法了,比如当你输入$value->的时候IDE应该提示这个实体上有哪些方法,然后你找到自己需要的照着敲就是了,这种写法对编辑器是比较友好的。如果对返回的东西不熟悉的话使用var_dump()这个函数把它打印出来看一下就知道了。

    当然这里只是最简单的几种用法如果想了解更多的用法可以去看DoctrineORMEntityRepository这个类或继续看我下面的讲解。

    往往有时间就上面这些查询是无法满我们的需求的,我们还需要更多的更加复杂的查询功能,当然DoctrineORMEntityRepository也提供了给开发人员自己定更复杂的语句的方法,比如:

    • createQueryBuilder
    • createNamedQuery
    • createResultSetMappingBuilder
    • createNativeNamedQuery

    想知道更多可以去doctrine的官网查询更多的相关资料(前提是你英文足够好),当然它提供的这些方法我不建议在控制器上使用,这个时候我们最好把它单独出来,减少代码冗余提高复用性。这个时候我们就要使用到Repository了,还记得上篇文章我对Repository的一些简单的介绍吗?什么?不知道?回去把我写的文章抄写三遍...

    Repository

    在最上面的Channel类的注释里有没有发现@Entity(repositoryClass="EntityRepositoryChannelRepository")这么一段参数; 这个就是可以自己扩展的库,也就相当于自己在CI框架里写的MODEL类,如果我们要使用它的话需要执行一条创建对它进行创建:

    php doctrine orm:generate:repositories ./model

    执行上面命令后会把./model下面的所有实体如果设置了@Entity的实例全部创建一个 Repository 类库;

    // ./app/model/Entity/Repository/ChannelRepository.phpnamespace EntityRepository;use DoctrineORMEntityRepository;//use DoctrineORMQueryExprJoin;/** * ChannelRepository * * This class was generated by the Doctrine ORM. Add your own custom * repository methods below. */class ChannelRepository extends EntityRepository{}
    

    然后我们再回到 Channel 实体把刚刚创建的 ChannelRepository 库给引用进来并继承它;

    use EntityRepositoryChannelRepository;class Channel extends ChannelRepository{}
    

    这样的话,当我们加载一个实体后就可以实现这个实体里自己写的扩展方法了,非常 方便呢,后面我会讲;

    OK创建实体基本的方法大概就是上在这些,如有不清楚的地方请大家在下面评论区留言。。。

    扩展库 Repository

    咱们上一篇文章提到过Repository这个东西,如果有不清楚的可以点这里《CodeIgniter Doctrine2基本使用》其实写在Repository里就是为了同样的东西可以重复调用,提高代码的复用性。

    那天下面我就举几个例子吧,说这么还不如直接看代码。

    /**     * 根据渠道tag查询渠道信息     * @param $tag     * @return array     */    public function findChannelByTag    {        return $this->_em->createQueryBuilder()            ->select            ->from('EntityChannel', 'c')            ->where('c.channelTag = :tag')                        ->setParameter( 'tag', $tag )            ->getQuery()->getSingleResult();    }    /**     * 分页查找所有渠道     * @param $page     * @return mixed     */    public function findChannelPage    {        return $this->_em->createQueryBuilder()            ->select            ->from('EntityChannel', 'c')            ->orderBy('c.channelId', 'desc')            ->setMaxResults            ->setFirstResult( (($page -1 ) * 10 ) )            ->getQuery()->getResult();    }    /**     * 统计渠道数量     * @return mixed     */    public function countChannelAll()    {        return $this->_em->createQueryBuilder()            ->select("COUNT(c.channelId)")            ->from('EntityChannel', 'c')            ->getQuery()->getSingleScalarResult();    }
    

    如以上写的这些方法,相信大多数人都能看得懂吧,基本每个方法都是这样,更多的方法请查看DoctrineORMQueryBuilder这个类。

    • createQueryBuilder()创建一个查询生成器
    • select()需要查询的字段,要注意的是这里写的字段是EntityChannel里面成员属性所对应的字段,可以自定义查询的字段。比如select('c.channelId,c.channelTag')它只会返回两个字段数据。如果有关联查询如innerJoin,leftJoin等关联查询那么可以这样写select当然我这样写的比较少,基本都是使用ManyToOne、OneToOne等形式来进行关联查询,这个我后面再讲,当然也可以通过addSelect()这个方法来设置多个查询实体
    $this->_em->createQueryBuilder()    ->select     ->addSelect     ->from('EntityUser', 'u')     ->leftJoin('EntityChannel', 'c');
    
    • from()这个无需多讲就是查询哪个实体,写它的全名空间就好了,这里传两个参数,第二个是别名
    • where()这个也不用多解释了,传的查询条件。可以写多个比如where('c.channelTag = :tag AND c.channelId = :id')当然,如果不想这样写的话还可以通过andWhere()方法来设置条件。
    • orWhere()与上面一样,用过*CodeIgniter*框架的应该都知道吧,用法都差不多,得配合where()方法使用
    $this_em->createQueryBuilder()->select->from('EntityChannel', 'c')->where('c.channelId = :id')->orWhere('c.channelTag = :tag')
    
    • delete()这个也很好理解,当然就是删除啦如下列子
    $this->_em->createQueryBuilder()->delete('EntityChannel', 'c')    ->where('c.channelId = :id')    ->setParameter;
    
    • update()这个就是更新数据的方法,需要配合下面的set()方法进行使用
    $this->_em->createQueryBuilder()->update('EntityChannel', 'c')->set('c.channelName', "{$channelName}")->where('c.channelId = 1');
    
    • set()这个也不用多讲解了,配合上面的update()方法使用上面有例子
    • join()、innerJoin()、leftJoin()关联查询这几个方法的使用方式类型我下面就写一个例子好了,对了这里需要把Join这个类给加载进来,use DoctrineORMQueryExprJoin因为到现在为止我项目用得比较少,非常少基本都是用ManyToOne()做的联查关于这个联查我将在下一篇文章进行讲解
    $this_em->createQueryBuilder()->select->from('EntityUser', 'u')->innerJoin('EntityChannel', 'c', Join::WITH, 'c.channelId = u.channelId');
    
    • setParameter()这个也很好理解,就是设置前面的where条件的参数,上面的where方法我不是定义了:id:tag这两个flag,这个方法就是对它们进行传参的,这个上面也有例子,我就不再这里凑字数了
    • setParameters()这个方法跟上同那个传参数的方法似,也比较常用,传多个参数
    setParameters(new ArrayCollection(array(    new Parameter,       new Parameter   ))); 
    
    • groupBy()、addGroupBy()这两个也不用多说吧,就是goup by 怎么整的好像在讲mysql的用法似得
    $this->_em->createQueryBuilder()->select->from('EntityUser', 'u')->groupBy('u.channelId');
    
    • having()、andHaving()、orHaving()having的用法跟一样吧,这个用得比较少,因为性能比较低,不太喜欢在mysql上进行过多的运算
    • orderBy()、addOrderBy()这两个也不用多说了,就是排序嘛,不需要写例子吧...上面有
    • getQuery()这个时候还没有生成结果集,只是做了一个查询?
    • getResult()返回多个结果集,最终返回的是一个多维数组对象,可以通过foreach进行遍历,遍历出来的value就是它的实体
    • getSingleScalarResult()这个就是返回一个值吧,我只有统计的时候用过它
    • getSingleResult()返回单个结果集,也就是一个实体对象
    • getDql()返回生成的DQL语句?

    上面写了辣么多,我怎么感觉自己好像是在讲怎么操作数据库呢?总结就是需要复用的稍微复杂一点的查询就放在Repository里吧,方便你我他。

    好了Repository就暂时先讲到这里吧,下一节我们讲ManyToOne、OneToMany、OneToOne、ManyToMany的查询。

    原文目录:

    加载实体

    既然我们实体及实体库已经创建好了,那要如何使用它呢?

    首先先把需要用的这个实体给加载进来,我们可以使用:$this->em->getRepository方法,当然前提是你必须先加载Doctrine这个类库文章《CodeIgniter 3.0整合Doctrine2》好像有讲,可以去看看,不想看的话我下面再写一下

    后面写的 $this->em 的由来
    平时我们在CI创建一个控制器时需要继承一个父控制器一般在 ./app/core/MY_Controller.php 不要问我为什么要这样写,不明白的回去把CodeIgniter框架抄写三遍
    然后我们在 MY_Controller 控制器的 __function() 方法载入 Doctrine 扩展类可以参考下面代码

    // ./app/core/MY_Controller.phpclass MY_Controller extends Controller {protected $em;function __construct(){parent::__construct();$this->load->library('doctrine');        /** @var  $em DoctrineORMEntityManager */        $em = $this->doctrine->em;        $this->em = $em;}}
    

    然后我们就可以使用$em这个成员了;

    要如何使用呢?

    比如我们创建一个控制器就叫 channel.php 好了

    class Channel extends MY_Controller{function __construct(){parent::__construct();}public function index(){/** @var  $channelRepository EntityChannel */$channelRepository = $this->em->getRepository('EntityChannel');$channelRepository->findAll();}}
    

    为什么要加/** @var $channelRepository EntityChannel */这样一个注释呢?

    大家可别小看这种注释,很有用的,不信的话你按住command+鼠标左键点一下试试(在大多IDE上都是支持的,Sublime Text也可以使用)

    好了,加载实体基本上就算是讲完了。

    操作实体

    上面我们已经把实体给加载进来了,现在我们要对数据库过行相关操作;其实呢我们操作实体就相当于是在操作数据库表,每一个实体就相当于是一张表,它于表是一种映射关系。

    插入一条数据

    持入一条数据首先需要把这个实体实例化,也就是new一下这个实体我们才能使用它,比如以下代码:

    /** @var  $channel EntityChannel */$channel = new EntityChannel();$channel->setChannelTag()->setChannelName();$this->em->persist( $channel );$this->em->flush();
    

    OK我来简单的讲解一下上面的代码,这里我们需要吧。我们知道这张表一共有四个字段分别是

    • channelId
    • channelTag
    • channelName
    • channelTime

    然后我们需要分别对这些字段设置一些值,那我们就需要用到EntityChannel这个实体里刚刚生成的setter方法了。 那为什么我只set了两直字段呢?

    1. channel_id 是一个主键我们不需要对它进行操作,可以看到主建是没有setter方法的所以不需要设置这个字段的值,执行前它是空的如果成功拷入数据后这个字段就会是刚刚插入后返回的ID
    2. channel_time 上面已经讲到了 我们在EntityChannel这个实体的构造函数里已经对它进行赋值了,所以它是有内容的,不信的话你var_dump这个实体看它的成员的值

    设置完后我们需要调用$this->em->persist这人方法把设置好的EntityChannel这个实体塞进去,注意:此时并没有执行SQL语句进入数据。我们需要调用一下$this->em->flush()这个方法执行SQL语句,如果想看它生成的是什么样的SQL的话可以进入数据库输入以下命令:

    • show variables like '%gene%';
    Variable_name Value
    general_log OFF
    general_log_file /opt/rh/mysql55/root/var/lib/mysql/default.log

    我们可以看到现在所有的数据库操作日志状态是OFF我们需要所它设置成ON,执行以下命令

    • set global general_log = ON;

    /opt/rh/mysql55/root/var/lib/mysql/default.log这个就是操作日志,我们可以tail -f一下它然后可以可看到以后我们地数据库的所有操作了。

    查询操作

    原文链接:

    本文由澳门402永利com发布于编程应用,转载请注明出处:Doctrine2基本使用

    关键词:

上一篇:Python生成器

下一篇:没有了