- symfony/
- Symfony ORM原则:使用由外键组成的复合主键持久化集合
Symfony ORM原则:使用由外键组成的复合主键持久化集合
Symfony ORM原则:使用由外键组成的复合主键持久化集合,symfony,orm,doctrine-orm,doctrine-orm-postgres,Symfony,Orm,Doctrine Orm,Doctrine Orm Postgres,我猜这是一个条令错误(我已经在JIRA issue tracker上提交了一个问题),但如果只是用户错误,我决定将其发布在这里
提要
在具有复合主对象的联接表中持久化实体集合
由两个外键和一个元数据字段组成的密钥在某些情况下会失败。代码基于以下说明:
发行详情
成功:当要持久化的集合中的项目的外键1相同时,
并且外键2大于实体中任何现有主键中的外键2
和集合中的相关实体已正确持久化:
示例:GPA“在下方添加val”存在并具有评估值{“评估”:6,“值”:4}
我们将尝试添加一个新的评估值,其
我猜这是一个条令错误(我已经在JIRA issue tracker上提交了一个问题),但如果只是用户错误,我决定将其发布在这里
提要
在具有复合主对象的联接表中持久化实体集合
由两个外键和一个元数据字段组成的密钥在某些情况下会失败。代码基于以下说明:
发行详情
成功:当要持久化的集合中的项目的外键1相同时,
并且外键2大于实体中任何现有主键中的外键2
和集合中的相关实体已正确持久化:
代码
migration.sql
创建表评估
(
id bigserial不为空,
scale_id bigint不为空,
title varchar不为空,
传递布尔值不为NULL,
排名int,
主键(id)
);
创建表格评估量表
(
id bigserial不为空,
名称varchar不为空,
主键(id)
);
-- ...
创建表格坡度\点\平均值
(
id bigserial不为空,
名称varchar不为空,
额外的信用额度数字(4,2),
主键(id)
);
-- ...
创建表gpa\U评估值
(
等级\点\平均值\ id bigint不为空,
评估id bigint不为空,
点_值数值(4,2)不为空,
主键(评估id、分数id、平均id),
外键(评估id)参考评估,
外键(grade\u point\u average\u id)引用grade\u point\u average
);
Model/GradePointAverage.php
名称空间MyApp\Model;
使用条令\ORM\Mapping\Entity;
使用条令\ORM\Mapping\Id;
使用条令\ORM\Mapping\GeneratedValue;
使用条令\ORM\Mapping\Column;
//...
使用条令\公共\集合\集合;
使用条令\Common\Collections\ArrayCollection;
使用MyApp\Util\ConstructorArgs;
使用MyApp\Model\GradePointAverage\AssessmentValue;
// ...
/**
*@Entity(“MyApp\Repository\GradePointAverageRepository”)
*/
班级平均分
{
使用ConstructorArgs;
/**
*@Id
*@GeneratedValue
*@Column(type=“bigint”)
*
*@var int
*/
私人$id;
// ...
/**
*@OneToMany(targetEntity=“MyApp\Model\GradePointAverage\AssessmentValue”,mappedBy=“GradePointAverage”,cascade=“persist”)
*
*@var集合
*/
私人$assessmentValues;
// ...
/**
*@param数组$args
*/
公共函数构造(数组$args=[])
{
$this->assessmentValues=newarraycollection;
// ...
$this->handleArgs($args);
}
// ...
/**
*@返回集合
*/
公共函数getAssessmentValues()
{
返回$this->assessmentValues;
}
/**
*@param ArrayCollection$assessmentValues
*/
公共函数setAssessmentValues(ArrayCollection$assessmentValues)
{
$this->assessmentValues=$assessmentValues;
}
/**
*@param AssessmentValue$AssessmentValue
*/
公共功能addAssessmentValue(AssessmentValue$AssessmentValue)
{
$this->assessmentValues->add($assessmentValue);
}
/**
*@param AssessmentValue$AssessmentValue
*/
公共功能removeAssessmentValue(评估值$AssessmentValue)
{
$this->assessmentValues->removelement($assessmentValue);
}
// ...
}
Model/GradePointAverage/AssessmentValue.php
名称空间MyApp\Model\GradePointAverage;
使用条令\ORM\Mapping\Entity;
使用条令\ORM\Mapping\Table;
使用条令\ORM\Mapping\Column;
使用条令\ORM\Mapping\Id;
使用条令\ORM\Mapping\GeneratedValue;
使用条令\ORM\Mapping\manytone;
使用条令\ORM\Mapping\JoinColumn;
使用MyApp\Model\GradePointAverage;
使用MyApp\Model\Assessment;
使用MyApp\Util\ConstructorArgs;
/**
*@Entity(“MyApp\Repository\GradePointAverage\AssessmentValueRepository”)
*@表(“gpa\U评估值”)
*/
班级评估价值
{
使用ConstructorArgs;
/**
*@Id
*@ManyToOne(targetEntity=“MyApp\Model\GradePointAverage”)
*/
私家车平均售价$1;
/**
*@Id
*@ManyToOne(targetEntity=“MyApp\Model\Assessment”)
*/
私人部门$评估;
/**
*@列(“点值”)
*
*@var浮动
*/
私人美元价值;
/**
*@param数组$args
*/
公共函数构造(数组$args=[])
{
$this->handleArgs($args);
}
/**
*@return-GradePointAverage
*/
公共函数getGradePointAverage()
{
返回$this->gradePointAverage;
}
/**
*@param GradePointAverage$GradePointAverage
*/
公共函数setGradePointAverage(GradePointAverage$GradePointAverage)
{
$this->gradePointAverage=$gradePointAverage;
}
/**
*@回报评估
*/
公共职能评估()
{
返回$this->assessment;
}
/**
*@param Assessment$Assessment
*/
公共职能评估(评估$Assessment)
{
$this->assessment=$assessment;
}
/**
*@返回浮动
*/
公共函数getValue()
{
返回$this->value;
}
/**
*@param float$value
*/
公共函数setValue($value)
{
$this->value=$value;
}
/**
*@回报评估表
*/
公共职能评估量表()
{
返回$t
CREATE TABLE assessment
(
id bigserial NOT NULL,
scale_id bigint NOT NULL,
title varchar NOT NULL,
passing boolean NOT NULL,
rank int,
PRIMARY KEY (id)
);
CREATE TABLE assessment_scale
(
id bigserial NOT NULL,
name varchar NOT NULL,
PRIMARY KEY (id)
);
-- ...
CREATE TABLE grade_point_average
(
id bigserial NOT NULL,
name varchar NOT NULL,
additional_credit_allowance numeric(4, 2),
PRIMARY KEY (id)
);
-- ...
CREATE TABLE gpa_assessment_value
(
grade_point_average_id bigint NOT NULL,
assessment_id bigint NOT NULL,
point_value numeric(4, 2) NOT NULL,
PRIMARY KEY (assessment_id, grade_point_average_id),
FOREIGN KEY (assessment_id) REFERENCES assessment,
FOREIGN KEY (grade_point_average_id) REFERENCES grade_point_average
);
namespace MyApp\Model;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\Column;
//...
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection;
use MyApp\Util\ConstructorArgs;
use MyApp\Model\GradePointAverage\AssessmentValue;
// ...
/**
* @Entity("MyApp\Repository\GradePointAverageRepository")
*/
class GradePointAverage
{
use ConstructorArgs;
/**
* @Id
* @GeneratedValue
* @Column(type="bigint")
*
* @var int
*/
private $id;
// ...
/**
* @OneToMany(targetEntity="MyApp\Model\GradePointAverage\AssessmentValue", mappedBy="gradePointAverage", cascade="persist")
*
* @var Collection
*/
private $assessmentValues;
// ...
/**
* @param array $args
*/
public function __construct(array $args = [])
{
$this->assessmentValues = new ArrayCollection;
// ...
$this->handleArgs($args);
}
// ...
/**
* @return Collection
*/
public function getAssessmentValues()
{
return $this->assessmentValues;
}
/**
* @param ArrayCollection $assessmentValues
*/
public function setAssessmentValues(ArrayCollection $assessmentValues)
{
$this->assessmentValues = $assessmentValues;
}
/**
* @param AssessmentValue $assessmentValue
*/
public function addAssessmentValue(AssessmentValue $assessmentValue)
{
$this->assessmentValues->add($assessmentValue);
}
/**
* @param AssessmentValue $assessmentValue
*/
public function removeAssessmentValue(AssessmentValue $assessmentValue)
{
$this->assessmentValues->removeElement($assessmentValue);
}
// ...
}
namespace MyApp\Model\GradePointAverage;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\Table;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\ManyToOne;
use Doctrine\ORM\Mapping\JoinColumn;
use MyApp\Model\GradePointAverage;
use MyApp\Model\Assessment;
use MyApp\Util\ConstructorArgs;
/**
* @Entity("MyApp\Repository\GradePointAverage\AssessmentValueRepository")
* @Table("gpa_assessment_value")
*/
class AssessmentValue
{
use ConstructorArgs;
/**
* @Id
* @ManyToOne(targetEntity="MyApp\Model\GradePointAverage")
*/
private $gradePointAverage;
/**
* @Id
* @ManyToOne(targetEntity="MyApp\Model\Assessment")
*/
private $assessment;
/**
* @Column("point_value")
*
* @var float
*/
private $value;
/**
* @param array $args
*/
public function __construct(array $args = [])
{
$this->handleArgs($args);
}
/**
* @return GradePointAverage
*/
public function getGradePointAverage()
{
return $this->gradePointAverage;
}
/**
* @param GradePointAverage $gradePointAverage
*/
public function setGradePointAverage(GradePointAverage $gradePointAverage)
{
$this->gradePointAverage = $gradePointAverage;
}
/**
* @return Assessment
*/
public function getAssessment()
{
return $this->assessment;
}
/**
* @param Assessment $assessment
*/
public function setAssessment(Assessment $assessment)
{
$this->assessment = $assessment;
}
/**
* @return float
*/
public function getValue()
{
return $this->value;
}
/**
* @param float $value
*/
public function setValue($value)
{
$this->value = $value;
}
/**
* @return AssessmentScale
*/
public function getAssessmentScale()
{
return $this->assessment->getScale();
}
}
namespace MyApp\Model;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\ManyToOne;
use MyApp\Model\Assessment\Scale;
use MyApp\Util\ConstructorArgs;
/**
* @Entity("MyApp\Repository\AssessmentRepository")
*/
class Assessment
{
use ConstructorArgs;
/**
* @Id
* @GeneratedValue
* @Column(type="bigint")
*
* @var int
*/
private $id;
// ...
/**
* @param array $args
*/
public function __construct(array $args = [])
{
$this->handleArgs($args);
}
/**
* @return int
*/
public function getId()
{
return $this->id;
}
// ...
}
namespace MyApp\Repository;
use Doctrine\ORM\EntityRepository;
// ...
use MyApp\Model\GradePointAverage;
class GradePointAverageRepository extends BaseRepository implements GradePointAverageRepositoryInterface
{
// ...
/**
* @param GradePointAverage $gradePointAverage
*/
public function save(GradePointAverage $gradePointAverage)
{
$this->getEntityManager()->persist($gradePointAverage);
$this->getEntityManager()->flush();
}
}
namespace MyApp\Repository\GradePointAverage;
use Doctrine\ORM\EntityRepository;
use MyApp\Model\GradePointAverage\AssessmentValue;
class AssessmentValueRepository extends EntityRepository
{
/**
* @param AssessmentValue $assessmentValue
*/
public function save(AssessmentValue $assessmentValue)
{
$this->getEntityManager()->persist($assessmentValue);
$this->getEntityManager()->flush();
}
}
namespace MyApp\Manager;
use InvalidArgumentException;
use Symfony\Component\Validator\ValidatorInterface;
use JMS\DiExtraBundle\Annotation\Service;
use JMS\DiExtraBundle\Annotation\InjectParams;
use JMS\SecurityExtraBundle\Annotation\PreAuthorize;
use Knp\Component\Pager\Pagination\PaginationInterface;
use MyApp\Repository\GradePointAverageRepository;
use MyApp\PaginationFactory\GradePointAveragePaginationFactoryInterface;
use MyApp\Model\GradePointAverage;
/**
* @Service("grade_point_average_manager")
*/
class GradePointAverageManager
{
/**
* @var GradePointAverageRepository
*/
private $gradePointAverageRepository;
/**
* @var GradePointAveragePaginationFactoryInterface
*/
private $gradePointAveragePaginationFactory;
/**
* @var ValidatorInterface
*/
private $validator;
/**
* @InjectParams
*
* @param GradePointAverageRepository $gradePointAverageRepository
* @param GradePointAveragePaginationFactoryInterface $gradePointAveragePaginationFactory
* @param ValidatorInterface $validator
*/
public function __construct(
GradePointAverageRepository $gradePointAverageRepository,
GradePointAveragePaginationFactoryInterface $gradePointAveragePaginationFactory,
ValidatorInterface $validator
)
{
$this->gradePointAverageRepository = $gradePointAverageRepository;
$this->gradePointAveragePaginationFactory = $gradePointAveragePaginationFactory;
$this->validator = $validator;
}
/**
* @PreAuthorize("isAllowedToManageTheGradePointAverage(#gradePointAverage)")
* @param GradePointAverage $gradePointAverage
* @throws InvalidArgumentException
*/
public function save(GradePointAverage $gradePointAverage)
{
$violationList = $this->validator->validate($gradePointAverage);
if ($violationList->count()) {
throw new InvalidArgumentException;
}
$this->gradePointAverageRepository->save($gradePointAverage);
}
}
namespace MyApp\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Log\LoggerInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Doctrine\Common\Collections\ArrayCollection;
use FOS\RestBundle\View\View;
use JMS\DiExtraBundle\Annotation\Service;
use JMS\DiExtraBundle\Annotation\InjectParams;
use JMS\SecurityExtraBundle\Annotation\PreAuthorize;
use Knp\Component\Pager\Pagination\PaginationInterface;
use MyApp\Manager\GradePointAverageManager;
use MyApp\Model\GradePointAverage;
use MyApp\Model\GradePointAverage\AssessmentValue;
/**
* @Service("grade_point_average_controller", parent="app.controller.abstract")
* @Route("/gpa", service="grade_point_average_controller")
*/
class GradePointAverageController extends BaseController
{
/**
* @var GradePointAverageManager
*/
private $gradePointAverageManager;
private $logger;
/**
* @InjectParams
*
* @param GradePointAverageManager $gradePointAverageManager
* @param LoggerInterface $logger
*/
public function __construct(GradePointAverageManager $gradePointAverageManager, LoggerInterface $logger)
{
$this->gradePointAverageManager = $gradePointAverageManager;
$this->logger = $logger;
}
// ...
/**
* @Route("/{id}", name="gpa.edit", requirements={"id" = "\d+"})
* @Method("PUT")
*
* @param Request $request
* @param GradePointAverage $gpa
* @return View
*/
public function editAction(Request $request, GradePointAverage $gpa)
{
$form = $this->formFactory->createNamed(null, 'gpa', $gpa, [
'method' => 'PUT',
]);
$form->handleRequest($request);
foreach ($gpa->getAssessmentValues() as $av) {
$this->logger->info('GPA ID PREVALIDATE IN CONTROLLER:'.$gpa->getId());
$this->logger->info('PREVALIDATE IN CONTROLLER ASSESSMENT VAL ASSESSMENT ID:'.$av->getAssessment()->getId());
$this->logger->info('PREVALIDATE IN CONTROLLER ASSESSMENT VAL POINTS:'.$av->getValue());
}
/*
// try reversing the order of the collection to see if that helps
$assessmentVals = $gpa->getAssessmentValues()->toArray();
$reversed = array_reverse($assessmentVals);
$reversedColl = new ArrayCollection($reversed);
$gpa->setAssessmentValues($reversedColl);
*/
if ($form->isValid()) {
foreach ($gpa->getAssessmentValues() as $av) {
$this->logger->info('GPA ID PRESAVE IN CONTROLLER:'.$gpa->getId());
$this->logger->info('PRESAVE IN CONTROLLER ASSESSMENT VAL ASSESSMENT ID:'.$av->getAssessment()->getId());
$this->logger->info('PRESAVE IN CONTROLLER ASSESSMENT VAL POINTS:'.$av->getValue());
}
$this->gradePointAverageManager->save($gpa);
return new View($gpa, 204);
}
return new View($form);
}
// ...
}
CREATE TABLE gpa_assessment_value
(
id bigserial NOT NULL,
grade_point_average_id bigint NOT NULL,
assessment_id bigint NOT NULL,
point_value numeric(4, 2) NOT NULL,
PRIMARY KEY (id,assessment_id, grade_point_average_id),
FOREIGN KEY (assessment_id) REFERENCES assessment,
FOREIGN KEY (grade_point_average_id) REFERENCES grade_point_average
);