php 如何在学说实体之间通过ID建立一对一的关系

ev7lccsx  于 2023-03-28  发布在  PHP
关注(0)|答案(2)|浏览(120)

我希望这是一个直接的过程,但似乎教义并不真的喜欢通过他们的ID链接实体的想法。
我想做的就是通过将一些字段从表中转移到一个新表来规范化一个表,而不是在原始表中添加一个新的引用字段来保存新的对应记录的ID,确保子表中的新记录将具有与其父行相同的ID。
下面是我的一个例子:
一个User实体,带有注解字段$user,用于将UserDetail实体中的列ID引用到其自身的ID

/**
 * @ORM\Table(name="user", options={"collate"="utf8_general_ci", "charset"="utf8", "engine"="InnoDB"})
 * @ORM\Entity
 */
class User extends Entity
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id

     /**
      * @ORM\OneToOne(targetEntity="UserDetail", cascade={"persist"})
      * @ORM\JoinColumn(name="id", referencedColumnName="id", nullable=true)
      */
     private $userDetail;

     ...
}

这里是UserDetail,去掉了ID的@GeneratedValue

/**
 * @ORM\Table(name="user_detail", options={"collate"="utf8_general_ci", "charset"="utf8", "engine"="InnoDB"})
 * @ORM\Entity
 */
class UserDetail extends Entity
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     */
    private $id;

    ...
}

在这一点上,我的期望是能够做到这样的事情:

$user = new User();
$userDetail = new UserDetail();

$user->setUserDetail($userDetail)

$entityManager->persist($user);
$entityManager->flush();

并将两条记录持久化到useruser_detail表中,这两条记录具有 identical ID,但实际情况是,如果没有为UserDetail的标识符定义任何策略,则教条将抱怨缺少ID Entity of type UserDetail is missing an assigned ID for field 'id'.
当然,也可以通过手动和多次调用来完成这项工作

$user = new User();
$entityManager->persist($user);
$entityManager->flush();

$userDetail = new UserDetail();
$userDetail->setId($user->getId)    
$user->setUserDetail($userDetail)

$entityManager->persist($user);
$entityManager->flush();

但是我仍然希望有一个正确的配置(注解)可以帮助我避免这样的额外步骤,并将通过实体ID处理一对一关系的工作留给Doctrine。

wbgh16ku

wbgh16ku1#

这是未经测试的,但我认为以下可能工作,根据文档(http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/composite-primary-keys.html):

/**
     * @ORM\Table(name="user_detail", options={"collate"="utf8_general_ci", "charset"="utf8", "engine"="InnoDB"})
     * @ORM\Entity
     */
    class UserDetail extends Entity
    {
        /**
         * @var integer
         *
         * @ORM\OneToOne(targetEntity="User")
         * @ORM\JoinColumn(name="id", referencedColumnName="id")
         * @ORM\Id
         */
        private $user;

    ...
    }
bpzcxfmw

bpzcxfmw2#

我成功地创建了一个一对一的关系,其中主键也是外键。请参阅下面:
汽车实体:

/**
 * @ORM\Table(name="cars")
 * @ORM\Entity(repositoryClass="App\Repository\CarRepository") 
 */
class Car
{
    /**
     * @ORM\OneToOne(targetEntity="CarConfiguration", mappedBy="car")
     */
    private ?CarConfiguration $carConfiguration = null;
    
    public function getCarConfiguration(): ?CarConfiguration
    {
        return $this->carConfiguration;
    }

    public function setCarConfiguration(CarConfiguration $carConfiguration): void
    {
        $this->carConfiguration = $carConfiguration;
    }
}

轿厢配置实体:

/**
 * @ORM\Table(name="car_configurations")
 * @ORM\Entity()
 */
class CarConfiguration
{
    /**
     * @ORM\Id
     * @ORM\JoinColumn(name="car_id", referencedColumnName="id", unique=true, nullable=false, onDelete="CASCADE")
     * @ORM\OneToOne(targetEntity="Car", inversedBy="carConfiguration", cascade={"all"})
     */
    private Car $car;

    /**
     * @ORM\Column(name="has_radio", type="boolean")
     */
    private bool $hasRadio;

    public function __construct(Car $car, bool $hasRadio = false)
    {
        $this->car = $car;
        $this->hasRadio = $hasRadio;
    }

    public function getCar(): Car
    {
        return $this->car;
    }

    public function hasRadio(): bool
    {
        return $this->hasRadio;
    }

    public function setHasRadio(bool $hasRadio): void
    {
        $this->hasRadio = $hasRadio;
    }
}

Car repository:

class CarRepository extends EntityRepository
{
    public function persist(Car $car): void
    {
        $entityManager = $this->getEntityManager();
        $entityManager->persist($car);
    }

    public function flush(): void
    {
        $entityManager = $this->getEntityManager();
        $entityManager->flush();
    }   
}

客户端代码:

class AwesomeCommand extends Command
{
    private CarRepository $carRepository;
    
    public function __construct(CarRepository $carRepository) {
        parent::__construct();
        $this->carRepository = $carRepository;
    }
    
    protected function execute(InputInterface $input, OutputInterface $output): void
    {
        $car = $this->carRepository->find(1234);

        $carConfiguration = new CarConfiguration($car, true);
        $car->setCarConfiguration($carConfiguration);

        $this->carRepository->persist($car);
        $this->carRepository->flush();
    }
}

链接:
https://www.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/composite-primary-keys.html#use-case-2-simple-derived-identity

相关问题