首页 > 解决方案 > 主键中的 Doctrine 多租户缺失值(带 2 个 PK)

问题描述

我正在为 Doctrine 开发一个多租户系统。我遇到了一个例外,说

ContactBundle\Entity\Contact 上的主键 groupId 缺少值

我的多租户工作方式是让来自不同组织的数据由它们的 groupId 分隔。这样每个组织都可以有一个 id=1 并且不会违反任何规则,因为它们的 groupId 和 Id 的组合是使记录独一无二的原因。

这意味着您可以拥有

记录 1:id = 1 groupId = 1

记录 2:id = 1 groupId = 2

这将是有效的。

我遇到的问题是我不确定如何传入 groupId 以便在它为我的关联进行连接时传递,因此它会引发该错误。由于当前查看的项目的 group_id 应该与为联系人和组织列出的相同,我将如何将当前项目的 groupId 传递给联系人和组织的查询?这样它就可以提取正确的记录,并且不会抱怨缺少主键。

下面是我列出的项目实体。

<?php

namespace ProjectBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Project
 *
 * @ORM\Table(name="project")
 * @ORM\Entity(repositoryClass="ProjectBundle\Repository\ProjectRepository")
 */
class Project
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     */
    private $id;

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

    /**
     * @var string
     *
     * @ORM\Column(name="description", type="string", length=2500)
     */
    private $description;

    /**
     * @var int
     *
     * @ORM\OneToOne(targetEntity="ContactBundle\Entity\Contact", inversedBy="projects")
     * @ORM\JoinColumn(name="contact_id", referencedColumnName="id")
     *
     */
    private $contactId;


    /**
     * @var int
     *
     * @ORM\OneToOne(targetEntity="ContactBundle\Entity\Organization", inversedBy="projects")
     * @ORM\JoinColumn(name="organization_id", referencedColumnName="id")
     */
    private $organizationId;


    /**
     * @var int
     *
     * @ORM\Column(name="group_id", type="integer")
     * @ORM\Id
     */
    private $groupId;

    public function __construct($id, $groupId){
        $this->id = $id;
        $this->groupId = $groupId;
    }

    /**
     * Get id
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     *
     * @return Project
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set description
     *
     * @param string $description
     *
     * @return Project
     */
    public function setDescription($description)
    {
        $this->description = $description;

        return $this;
    }

    /**
     * Get description
     *
     * @return string
     */
    public function getDescription()
    {
        return $this->description;
    }

    /**
     * Set contactId
     *
     * @param integer $contactId
     *
     * @return Project
     */
    public function setContactId($contactId)
    {
        $this->contactId = $contactId;

        return $this;
    }

    /**
     * Get contactId
     *
     * @return int
     */
    public function getContactId()
    {
        return $this->contactId;
    }

    /**
     * Set organizationId
     *
     * @param integer $organizationId
     *
     * @return Project
     */
    public function setOrganizationId($organizationId)
    {
        $this->organizationId = $organizationId;

        return $this;
    }

    /**
     * Get organizationId
     *
     * @return int
     */
    public function getOrganizationId()
    {
        return $this->organizationId;
    }
}

我还将给你们我的 find() 和 findAll() 替代品,因为我当前的系统需要 groupId 来获得正确的记录。

/**
 * @param integer $groupId
 * @param integer $id
 */
public function findDataCollection(int $groupId)
{
    $qb = $this->repository->createQueryBuilder('e');
        $qb
            ->andWhere('e.groupId = :groupId')
            ->setParameter('groupId',$groupId);
        return $qb->getQuery()->getResult();
}

/**
 * @param integer $groupId
 * @param integer $id
 */

public function findData(int $groupId, $id)
{
    if(empty($id)){
        return false;
    }
    $qb = $this->repository->createQueryBuilder('e');
    $qb
        ->andWhere('e.id = :id')
        ->andWhere('e.groupId = :groupId')
        ->setParameter('id', $id)
        ->setParameter('groupId',$groupId);
    $data =  $qb->getQuery()->getOneorNullResult();
    return $data;
}

非常感谢各位!

标签: phpsymfonydoctrinemulti-tenant

解决方案


写下我的评论作为答案,因为它们需要更多的空间。所以不,我建议:我建议您将复合键(groupid)的第二部分替换为与组实体的实际关联,而不是手动管理的 id 字段(https://www.doctrine -project.org/projects/doctrine-orm/en/2.6/tutorials/composite-primary-keys.html#use-case-1-dynamic-attributes)。

至于您最初的问题,我实际上不确定您的问题是什么。如果您有可用的 Project 实体,您可以通过相关的 getter 直接访问连接的联系人和组织。

我不确定您的关联是否为您的用例正确定义;您已将关联定义为您的项目的一对一关系,这基本上意味着除了一个项目有一个联系人并属于一个组织之外,反过来说一个联系人只能有一个项目而一个组织可以只有一个项目......即它们听起来应该被定义为ManyToOne关联(?)


推荐阅读