【问题标题】:Persist create new entity while already exists (Ont-To-Many Many-To-One relation)在已经存在的情况下坚持创建新实体(Ont-To-Many Many-To-One 关系)
【发布时间】:2017-09-16 09:03:59
【问题描述】:

我有一个使用 Symfony3/Doctrine2 Rest Api 的 Angular4 应用程序。

在 Angular 和 Symfony 中,我都有这些实体:

  • 表节点
  • 节点

Table和Node的关系是:

表(OneToMany)TableNode(多对一)节点

什么是与属性的“多对多”关系。

在 Angular 应用程序中,我创建了一个新表(形成一个与 Symfony 应用程序中的表实体具有完全相同属性的 TableModel)。 此表包含几个来自 Api 的 Node 实体(因此它们已经存在于我的数据库中)。

我想要的是创建一个包含新 TableNode 实体的新表,并且每个 TableNode 都应该包含现有的 Node 实体。

当我想将我的表保存在数据库中时,我通过 Put 操作调用我的 Api:

/**
 * PUT Route annotation
 * @Put("/tables")
 */
public function putTableAction(Request $request)
{
    $em         = $this->getDoctrine()->getManager('psi_db');
    $serializer = $this->container->get('jms_serializer');
    $dataJson   = $request->query->get('table');
    $table      = $serializer->deserialize($dataJson, Table::class, 'json');

    // Here, my $table has no id (that's ok), the TableNode subentity has no id (ok) and my Node subentity already have an id (because they come from the db)

    $em->persist($table);

    // Here, my $table has a new id (ok), my TableNode has a new id (ok) BUT my Node subentity have a NEW id, so it will be duplicated 

    $em->flush();

    $view = $this->view();
    $view->setData($table);
    return $this->handleView($view);
}

我尝试使用 $em->merge($table) 而不是 $em->persist($table) 并且我的节点子实体保留了自己的 ID(因此它们可能不会在刷新中重复)但是表和tableNode 没有 id (null) 并且没有持久化。

我找到的唯一解决方案是遍历 TableNode 实体,从数据库中检索 Node 实体并执行 tableNode->setNode :

$tns = $table->getTableNodes();
foreach ($tns as $tn) {
    $nodeId = $tn->getNode()->getId();
    $dbNode = $nodeRepo->find($nodeId);
    $tn->setNode($dbNode);
}

但这不是一个好的解决方案,因为我在循环中进行 db 搜索,并且一个表可能包含一百多个 TableNode/Node,因此可能会占用大量资源。

有人有更清洁的解决方案吗? 谢谢。

编辑:添加类

表格:

/**
 * Table_
 * Doctrine "Table" is a reserved name, so we call it Table_
 *
 * @ORM\Table(name="psi_table")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\Table_Repository")
 *
 * @ExclusionPolicy("all")
 */
class Table_
{
    public function __construct()
    {
        $this->tNodes = new ArrayCollection();
    }

    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     *
     * @Expose
     */
    private $id;

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

    /**
     * @var \stdClass
     *
     * @ORM\Column(name="author", type="object", nullable=true)
     *
     * @Expose
     */
    private $author;

    /**
    * @var \stdClass
    *
    * @ORM\OneToMany(targetEntity="AppBundle\Entity\TableNode", mappedBy="table", cascade={"persist"})
    *
    * @Expose
    * @Type("ArrayCollection<AppBundle\Entity\TableNode>")
    * @SerializedName("tNodes")
    */
    private $tNodes;
}

表节点:

/**
 * TableNode
 *
 * @ORM\Table(name="psi_table_node")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\TableNodeRepository")
 *
 * @ExclusionPolicy("all")
 */
class TableNode
{
    public function __construct($table = null, $node = null, $position = null)
    {
        if($table) $this->table = $table;
        if($node) $this->node = $node;
        if($position) $this->position = $position;
    }

    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     *
     * @Expose
     */
     private $id;

    /**
     * @var integer
     *
     * @ORM\Column(name="position", type="integer")
     *
     * @Expose
     */
    private $position;

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

    /**
    * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Table_", inversedBy="tNodes", cascade={"persist"})
    * @ORM\JoinColumn(nullable=false)
    *
    * @Expose
    * @Type("AppBundle\Entity\Table_")
    */
    private $table;

    /**
    * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Node", inversedBy="tables", cascade={"persist", "merge"})
    * @ORM\JoinColumn(nullable=false)
    *
    * @Expose
    * @Type("AppBundle\Entity\Node")
    */
    private $node;
}

节点:

/**
 * TableNode
 *
 * @ORM\Table(name="psi_table_node")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\TableNodeRepository")
 *
 * @ExclusionPolicy("all")
 */
class TableNode
{
    public function __construct($table = null, $node = null, $position = null)
    {
        if($table) $this->table = $table;
        if($node) $this->node = $node;
        if($position) $this->position = $position;
    }

    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     *
     * @Expose
     */
    private $id;

    /**
     * @var integer
     *
     * @ORM\Column(name="position", type="integer")
     *
     * @Expose
     */
    private $position;

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

    /**
    * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Table_", inversedBy="tNodes", cascade={"persist"})
    * @ORM\JoinColumn(nullable=false)
    *
    * @Expose
    * @Type("AppBundle\Entity\Table_")
    */
    private $table;

    /**
    * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Node", inversedBy="tables", cascade={"persist", "merge"})
    * @ORM\JoinColumn(nullable=false)
    *
    * @Expose
    * @Type("AppBundle\Entity\Node")
    */
    private $node;
}

提交的数据(示例):

{"tNodes":[{"id":0,"position":0,"groupSocio":"group1","node":{"id":683,"frontId":"1502726228584","level":"synusy","repository":"baseveg","name":"A synusy from my Angular app!","geoJson":{"type":"FeatureCollection","features":[{"type":"Feature","properties":[],"geometry":{"type":"Point","coordinates":[-10.0634765625,42.0982224112]}}]},"lft":1,"lvl":0,"rgt":2,"children":[{"id":684,"frontId":"1502726228586","level":"idiotaxon","repository":"baseflor","name":"poa annua","coef":"1","geoJson":{"type":"FeatureCollection","features":[{"type":"Feature","properties":[],"geometry":{"type":"Point","coordinates":[-10.0634765625,42.0982224112]}}]},"lft":1,"lvl":0,"rgt":2,"validations":[{"id":171,"repository":"baseflor","repositoryIdTaxo":"7075","repositoryIdNomen":"50284","inputName":"poa annua","validatedName":"Poa annua L."}]}],"validations":[]}}]}

【问题讨论】:

  • 请向我们展示 Table、TableNode 和 Node 类中的 JMSSerializer 注释。还显示您提交的请求 URL 示例(或 $dataJson 的值)
  • 我编辑了帖子并添加了询问信息。谢谢
  • 你打错了 - 你添加了两次 TableNode,并没有添加 Node 类。

标签: symfony doctrine


【解决方案1】:

putTableAction 的目的是:

  • 创建 Table_ 的新实例
  • 创建 TableNode 的新实例
  • 不使用 节点

意思是:

1.您无需提交任何Node的详细信息。 Id 字段就足够了:

{"tNodes":[{"id":0,"position":0,"groupSocio":"group1","nodeId": 683}]}

2.您可以在TableNode中再添加一个字段,名为$nodeId,并与DB中的“node”字段进行映射。该字段的目的是为了简化反序列化,在所有其他地方都可以使用 $node 字段。

/**
 * @var integer
 *
 * @ORM\Column(name="node", type="integer")
 *
 * @Expose
 */
private $nodeId;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-21
    • 2016-09-05
    • 1970-01-01
    • 2014-01-11
    • 2020-10-20
    • 1970-01-01
    相关资源
    最近更新 更多