2014-01-15 2 views
0

붙어있어 :-)Symfony2 단방향 ManyToMany 컬렉션 양식

아마도 내 연구에 잘못된 키워드가있을 수 있습니다. 그러나 나는 빠져 나가지 않습니다. 그래서 한 군중이 나를 도울 수 있기를 바랍니다!

난 단방향 ManyToMany 협회 있습니다. 내가 양식을 제출 (따라서 유지) 할 때, 다음과 같은 에러가 발생합니다

A new entity was found through the relationship 'TrainerInnenPool\AppBundle\Entity\Trainer#applicationFields' that was not configured to cascade persist operations for entity: TrainerInnenPool\AppBundle\Entity\[email protected]

내가 할

는 "폭포가 지속"새 법인은 실제로 이미 존재하는 생성됩니다.

  • 트레이너
  • ApplicationField 트레이너가 ApplicationField에 단방향 ManyToMany 협회가

:

class Trainer { 

    public function __construct() 
    { 
     $this->applicationFields = new ArrayCollection(); 
    } 

    [...] 

    /** 
    * @ORM\ManyToMany(targetEntity="ApplicationField") 
    */ 
    protected $applicationFields; 

ApplicationField을 자체 -을 가지고

나는 2 엔티티가 OneToMany 협회 참조 :

class ApplicationField { 

    public function __construct() { 
     $this->children = new ArrayCollection(); 
    } 

    [...] 

    /** 
    * @ORM\OneToMany(targetEntity="ApplicationField", mappedBy="parent") 
    */ 
    private $children; 

    /** 
    * @ORM\ManyToOne(targetEntity="ApplicationField", inversedBy="children") 
    * @ORM\JoinColumn(name="parent_id", referencedColumnName="id") 
    */ 
    private $parent; 

트레이너 - ApplicationField 연결을 추가 할 수있는 양식을 만들고 싶습니다.

class ApplicationFieldCollectionType extends AbstractType 
{ 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     $builder 
      ->add('applicationFields', 'collection', array(
       'type'   => new ApplicationFieldType(), 
       'allow_add' => true, 
       'label' => false 
       )) 
     ; 
    } 

    public function setDefaultOptions(OptionsResolverInterface $resolver) 
    { 
     $resolver->setDefaults(array(
      'data_class' => 'TrainerInnenPool\AppBundle\Entity\Trainer', 
     )); 
    } 

임베디드 타입은 다음과 같다 : 따라서

나는 ApplicationFieldCollectionType이

class ApplicationFieldType extends AbstractType 
{ 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     $builder->add('applicationFieldName', 'entity', array(
       'class' => 'TrainerInnenPoolAppBundle:ApplicationField', 
       'label' => false, 
       'mapped' => false, 
       'property' => 'name', 
       'query_builder' => function(EntityRepository $repository) { 
        return $repository->createQueryBuilder('application_field') 
         ->where('application_field.parent is NULL'); 
       } 
     )); 

     $builder->add('name', 'entity', array(
       'class' => 'TrainerInnenPoolAppBundle:ApplicationField', 
       'label' => false, 
       'property' => 'name', 
       'query_builder' => function(EntityRepository $repository) { 
        return $repository->createQueryBuilder('application_field') 
         ->where('application_field.parent = 1'); 
       } 
     )); 
    } 

    public function setDefaultOptions(OptionsResolverInterface $resolver) 
    { 
     $resolver->setDefaults(array(
      'data_class' => 'TrainerInnenPool\AppBundle\Entity\ApplicationField', 
     )); 
    } 

마지막 누락 된 부분 : 컨트롤러 :

public function editApplicationField($id, Request $request) 
    { 
     $entityManager = $this->getDoctrine()->getEntityManager(); 

     $trainer = $entityManager->getRepository('TrainerInnenPoolAppBundle:Trainer')->find($id); 

     $editForm = $this->createForm(new ApplicationFieldCollectionType(), $trainer); 

     if ($request->getMethod() == 'POST') { 

      $editForm->handleRequest($request); 

      $entityManager->flush(); 
     } 

나는 ApplicationField를 가져올 때 트레이너의 실체를 유지하려고 노력하고 있습니다.

 $editForm->handleRequest($request); 

     $af = $trainer->getApplicationFields(); 

     foreach ($af as $applicationField) { 
      $trainer->addApplicationField($applicationField); 
      $entityManager->persist($applicationField); 
     } 

     $entityManager->flush(); 

예외적으로 "중복 된 PRIMARY 항목"이 나올 수 있으므로이 작업을 수행 할 수 없습니다.

나는 명백한 점을 그리워합니다. 누군가가 나를 도울 수 있고 힌트를 주거나 방금 정보로 내 질문을 업데이트 할 수 있다면 너무 감사 할 것입니다.

종류에 관해서 ...

답변

0

그럼 당신은 당신이 ApplicationField과의 관계에 전체 개체를 유지하기를 원하기 때문에 주석을 { "계속"} 캐스케이드 =이 필요합니다. cascade = { "persist"}를 사용하지 않는다면 엔티티를 수동으로 유지해야합니다. 수동으로 엔티티를 지속 할 경우 라인

$trainer->addApplicationField($applicationField); 

을 제거 만이 계속 실행해야하므로

엔티티는 이미 트레이너에 추가됩니다.

이렇게하면됩니다. 시도 해봐. 하지만 효과는 계단식 지속성을 사용할 때와 같을 것이라고 생각합니다.제 생각에는 최종 해결책이 아니지만 문제를 이해하는 첫 번째 단계는 왜 수동 지속이 작동하지 않았는 지에 대한 것입니다.

+0

감사합니다. 실제로 이것은 첫 번째 접근 방법입니다. 관계는 지속됩니다. 여전히 새로운 ApplicationField 엔티티가 생성됩니다. 원래 ID가있는 ApplicationField 엔티티를 수동으로 지속하는 시점에도 여전히 참조가 손실되는 지점이 있다고 생각합니다. – mike

+0

오른쪽. 이미 그것에 대해 생각하고있어. 나는 단방향 manytomany를 사용한 적이 없으므로 처음 경험입니다. 트레이너에게 엔티티를 추가 할 때 엔티티가 이미 관리되고 있다는 것을 인식하지 못한다는 것이 문제라고 생각합니다. 다음을 시도해보십시오 : $ entityManager -> getUnitOfWork() -> getEntityState ($ applicationField). 엔티티가 관리 대상 또는 새 대상으로 표시되는지 확인하십시오. 새 메시지로 표시되면 요청을 제대로 처리하지 못하는 handleRequest 메서드가 문제입니다. – Tobias

+0

실제로 상태는 "2"-> STATE_NEW입니다. 그래서 나는 수동으로 모든 것을하지 않고 계속할 수있는 방법이 없다고 생각합니다 ...? – mike

1

귀하의 중첩 형 세터 때문에 누락 된 재산의 호출되지 않습니다 :

->add('applicationFields', 'collection', array(
       'type'   => new ApplicationFieldType(), 
       ... 
       'by_reference' => false 
       ... 

http://symfony.com/doc/current/reference/forms/types/collection.html#by-reference

당신은/삭제 가능한 추가 가능한 있습니다 수집 필드를 가질 계획 할 때 ("allow_add를", "allow_delete") 관련 엔티티에서 직접 setter를 호출 한 다음 원래 엔티티의 메소드를 연결하는 것이 아니라 연관을 빌드하기 위해 항상 "by_reference"=> false 옵션을 제공해야합니다.

희망이 도움이됩니다.