Symfony-Doctrine:在持久化实体后加入具有视图的表

时间:2017-09-01 13:54:35

标签: symfony view doctrine-orm orm entity

在我的数据库中,我有一个表T和一个视图V。 该视图包含我的表的一些列和其他数据(来自其他表)。

在Symfony中,我将我的视图声明为只读实体。

/**
  * @ORM\Table(name="V")
  * @ORM\Entity(readOnly=true, repositoryClass="AppBundle\Entity\Repository\VRepository")
  */
class V
{

在我的T实体中,我做了一个加入:

/**
  * @ORM\OneToOne(targetEntity="V")
  * @ORM\JoinColumn(name="T_id", referencedColumnName="V_id")
  */
 private $view;

我只是添加了吸气剂:

/**
 * Get view
 *
 * @return \AppBundle\Entity\V
 */
public function getView()
{
     return $this->view;
}

当我想阅读和显示数据时,一切运作良好。

但是在保留新的T实体后我遇到了问题。 当我创建一个新的T实体(editAction()完美地工作)时,Symfony似乎丢失了我的表单的发布数据。

An exception occurred while executing 'INSERT INTO T (T_id, T_name, updated_at) VALUES (?, ?, ?)' with params [null, null, "2017-09-01 15:30:41"]:

SQLSTATE[23000]: Integrity constraint violation: 1048 Field 'T_id' cannot be empty (null)

当我删除$view属性的ORM注释时,它会在数据库中正确创建我的新记录T

我认为问题是由于V实体(我的SQL视图中的记录)在创建T之后就存在了。当我在Symfony中持久保存/刷新数据时,V尚不存在。他们被创造了#34;在同一时间。

我尝试在@HasLifecycleCallbacks实体上添加Doctrine T,在@PostPersist方法上添加getView()事件,但它并没有改变任何内容...... < / p>

创建实体后,有什么想要区分Join?

我知道将视图用作Symfony的实体是不常见的,但我没有别的选择。

2 个答案:

答案 0 :(得分:0)

我刚检查过,可以正常使用Bidirectional One-To-One relation

在我的情况下,表定义如下:

create table T (`id` int(11) NOT NULL AUTO_INCREMENT, name varchar(100), primary key (id));
create view V as select id as entity, name, '123' as number from T;

T中的注释:

/**
 * @ORM\Table(name="T")
 * @ORM\Entity()
 */
class T
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255, nullable=true)
     */
    private $name;

    /**
     * @var V
     *
     * @ORM\OneToOne(targetEntity="V", mappedBy="entity")
     */
    private $view;

V中的注释:

/**
 * @ORM\Table(name="V")
 * @ORM\Entity(readOnly=true)
 */
class V
{
    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255, nullable=true)
     */
    private $name;

    /**
     * @var string
     *
     * @ORM\Column(name="number", type="string", length=255, nullable=true)
     */
    private $number;

    /**
     * @var T
     *
     * @ORM\Id
     * @ORM\OneToOne(targetEntity="T", inversedBy="view")
     * @ORM\JoinColumn(name="entity", referencedColumnName="id")
     */
    private $entity;

一个测试片段,证明它可以保存,更新和读取:

public function testCRUD()
{
    /** @var EntityManager $manager */
    $manager = $this->client->getContainer()->get('doctrine.orm.default_entity_manager');

    $t = new T();
    $t->setName('Me');

    $manager->persist($t);
    $manager->flush();

    $t->setName('He');
    $manager->flush();

    $manager->clear();
    /** @var T $t */
    $t = $manager->find(T::class, $t->getId());
    $this->assertEquals('He', $t->getView()->getName());
}

答案 1 :(得分:0)

基于@Maksym Moskvychev答案:倾向于双向一对一的关系。

T实体:

/**
 * @ORM\OneToOne(targetEntity="V", mappedBy="entity")
 */
 private $view;

V实体:

/**
 * @ORM\OneToOne(targetEntity="T", inversedBy="view")
 * @ORM\JoinColumn(name="V_id", referencedColumnName="T_id")
 */
 private $entity;
  
    

在发布addAction()表单(新T实例)后修复数据丢失。

  

在我列出所有T条记录的表格中:

$builder->add('entity', EntityType::class, array(
    'class'         => 'AppBundle:T',
    'choice_label'  => 'id',
    'query_builder' => function (EntityRepository $er) {
        return $er->createQueryBuilder('t')
            ->orderBy('t.name', 'ASC')
            ->setMaxResults(25);    // limit the number of results to prevent crash
    }
))
  
    

修复过于耗费资源的问题(显示25个实体而不是870 +)。

  

Ajax请求:

$(".select2").select2({
    ajax: {
        type        : "GET",
        url         : "{{ path('search_select') }}",
        dataType    : 'json',
        delay       : 250,
        cache       : true,
        data        : function (params) {
            return {
                q       : params.term, // search term
                page    : params.page || 1
            };
        }
    }
});

Select2的响应:

$kwd    = $request->query->get('q');    // GET parameters
$page   = $request->query->get('page');

$limit = 25;
$offset = ($page - 1) * $limit;

$em = $this->getDoctrine()->getManager();
$repository = $em->getRepository('AppBundle:V');

$qb = $repository->createQueryBuilder('v');
$where = $qb->expr()->orX(
    $qb->expr()->like('v.name', ':kwd'),
    $qb->expr()->like('v.code', ':kwd')
);
$qb->where($where);

// get the DQL for counting total number of results
$dql = $qb->getDQL();

$results = $qb->orderBy('m.code', 'ASC')
    ->setFirstResult($offset)
    ->setMaxResults($limit)
    ->setParameter('kwd', '%'.$kwd.'%')
    ->getQuery()->getResult();

// count total number of results
$qc = $em->createQuery($dql)->setParameter('kwd', '%'.$kwd.'%');
$count = count($qc->getResult());

// determine if they are more results or not
$endCount = $offset + $limit;
$morePages = $count > $endCount;

$items = array();
foreach ($results as $r) {    
    $items[] = array(
        'id'    => $r->getCode(),
        'text'  => $r->getName()
    );
}

$response = (object) array(
    "results"    => $items,
    "pagination" => array(
        "more" => $morePages
    )
);

if (!empty($results))
    return new Response(json_encode($response));