坚持在已经存在的情况下创建新实体(Ont-To-Many多对一关系)

时间:2017-09-16 09:04:00

标签: symfony doctrine

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

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

  • TableNode
  • 节点

表和节点之间的关系是:

表(OneToMany)TableNode(ManyToOne)节点

什么是" ManyToMany"与属性的关系。

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

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

当我想在db中保存我的表时,我通过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(因此它们可能不会在flush中重复)但是table和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);
}

但它不是一个好的解决方案,因为我在循环中进行数据库搜索,而一个表可能包含超过一百个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:

/**
 * 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":[]}}]}

1 个答案:

答案 0 :(得分:0)

putTableAction的目的是:

  • 创建表_
  • 的新实例
  • 创建 TableNode
  • 的新实例
  • 节点
  • 不执行任何操作

这意味着:

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

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

2.您可以向 TableNode 添加一个名为 $ nodeId 的字段,并将其映射到&#34; node&#34; DB中的字段。此字段的目的是简化反序列化,在所有其他地方您可以使用 $ node 字段。

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