Symfony-Doctrine:在持久化实体后加入 table 与视图
Symfony-Doctrine : join a table with a view after persisting entity
在我的数据库中,我有一个 table T
和一个视图 V
。
该视图包含我的 table 和其他数据(来自其他 table)的一些列。
在 Symfony 中,我将我的视图声明为只读实体。
/**
* @ORM\Table(name="V")
* @ORM\Entity(readOnly=true, repositoryClass="AppBundle\Entity\Repository\VRepository")
*/
class V
{
在我的 T
实体中,我做了一个 Join :
/**
* @ORM\OneToOne(targetEntity="V")
* @ORM\JoinColumn(name="T_id", referencedColumnName="V_id")
*/
private $view;
我只添加了 getter :
/**
* 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 中 persist/flush 数据时,V
还不存在。他们同时"created"
我试图在我的 T
实体上添加 Doctrine @HasLifecycleCallbacks
并在 getView()
方法上添加 @PostPersist
事件,但它没有改变任何东西...
创建实体后有什么想法可以改变 Join 吗?
我知道在 Symfony 中使用视图作为实体并不常见,但我别无选择。
我刚刚检查过,它 与 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());
}
基于@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;
Fix the loss of data after posting the addAction()
form (new T
instance).
在我列出所有 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
}
))
Fix the too consuming resources problem (show 25 entities instead of 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));
在我的数据库中,我有一个 table T
和一个视图 V
。
该视图包含我的 table 和其他数据(来自其他 table)的一些列。
在 Symfony 中,我将我的视图声明为只读实体。
/**
* @ORM\Table(name="V")
* @ORM\Entity(readOnly=true, repositoryClass="AppBundle\Entity\Repository\VRepository")
*/
class V
{
在我的 T
实体中,我做了一个 Join :
/**
* @ORM\OneToOne(targetEntity="V")
* @ORM\JoinColumn(name="T_id", referencedColumnName="V_id")
*/
private $view;
我只添加了 getter :
/**
* 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 中 persist/flush 数据时,V
还不存在。他们同时"created"
我试图在我的 T
实体上添加 Doctrine @HasLifecycleCallbacks
并在 getView()
方法上添加 @PostPersist
事件,但它没有改变任何东西...
创建实体后有什么想法可以改变 Join 吗?
我知道在 Symfony 中使用视图作为实体并不常见,但我别无选择。
我刚刚检查过,它 与 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());
}
基于@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;
Fix the loss of data after posting the
addAction()
form (newT
instance).
在我列出所有 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
}
))
Fix the too consuming resources problem (show 25 entities instead of 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));