Symfony无法保存manyToOne双向实体

时间:2015-09-21 10:15:12

标签: php symfony doctrine-orm

我有一个名为survey的实体,我有一个名为Creditcards

的实体

Creditcard使用survey

manyToOne相关联

survey使用Creditcard

oneToMany相关联

该调查有大量与财务相关的问题,这些问题会保存在survey表中,它还会询问用户的信用卡相关详细信息,然后将其保存在Creditcard表中,因为用户可以拥有多个卡片,以便他们可以添加多个卡片详细信息,这是manyToOneoneToMany发挥作用的地方。

这是我的Creditcard.orm.yml

ExampleBundle\Entity\Creditcards:
    type: entity
    table: creditcards
    id:
        id:
            type: integer
            id: true
            generator:
                strategy: AUTO
    fields:
        surveyId:
            type: integer
            column: survey_id
        balance:
            type: integer
        amountDue:
            type: integer
            column: amount_due
        interestRate:
            type: integer
            column: interest_rate
    manyToOne:
        survey:
            targetEntity: ExampleBundle\Entity\survey
            inversedBy: creditcards
            joinColumn:
                name: survey_id
                referencedColumnName: id
                onDelete: CASCADE
    lifecycleCallbacks: {   }

这是我的Creditcard实体

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
 * Creditcards
 */
class Creditcards
{
    /**
     * @var integer
     */
    private $id;

    /**
     * @var integer
     */
    private $surveyId;

    /**
     * @var integer
     */
    private $balance;

    /**
     * @var integer
     */
    private $amountDue;

    /**
     * @var integer
     */
    private $interestRate;

    /**
     * @var \ExampleBundle\Entity\Survey
     */
    private $survey;
    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set surveyId
     *
     * @param integer $surveyId
     * @return integer
     */
    public function setSurveyId($surveyId)
    {
        $this->surveyId = $surveyId;

        return $this;
    }

    /**
     * Get survey
     *
     * @return integer 
     */
    public function getSurveyId()
    {
        return $this->surveyId;
    }

    /**
     * Set balance
     *
     * @param integer $balance
     * @return Creditcards
     */
    public function setBalance($balance)
    {
        $this->balance = $balance;

        return $this;
    }

    /**
     * Get balance
     *
     * @return integer 
     */
    public function getBalance()
    {
        return $this->balance;
    }

    /**
     * Set amountDue
     *
     * @param integer $amountDue
     * @return Creditcards
     */
    public function setAmountDue($amountDue)
    {
        $this->amountDue = $amountDue;

        return $this;
    }

    /**
     * Get amountDue
     *
     * @return integer 
     */
    public function getAmountDue()
    {
        return $this->amountDue;
    }

    /**
     * Set interestRate
     *
     * @param integer $interestRate
     * @return Creditcards
     */
    public function setInterestRate($interestRate)
    {
        $this->interestRate = $interestRate;

        return $this;
    }

    /**
     * Get interestRate
     *
     * @return integer 
     */
    public function getInterestRate()
    {
        return $this->interestRate;
    }



    /**
     * Set survey
     *
     * @param \ExampleBundle\Entity\survey $survey
     * @return Creditcards
     */
    public function setSurvey(\ExampleBundle\Entity\survey $survey = null)
    {
        $this->survey = $survey;

        return $this;
    }

    /**
     * Get survey
     *
     * @return \ExampleBundle\Entity\survey
     */
    public function getSurvey()
    {
        return $this->survey;
    }
    public function addSurvey(\ExampleBundle\Entity\survey $survey)
    {
        $survey->addCreditcard($this);

        $this->survey->add($survey);
    }
}

这是我的survey.orm.yml

它很长,所以我会删除它的一部分以使其与问题

相关
ExampleBundle\Entity\survey:
    type: entity
    table: survey
    id:
        id:
            type: integer
            id: true
            generator:
                strategy: AUTO
    fields:
        homeLoanMonthlyRepayments:
            type: integer
            column: home_loan_monthly_repayments
            nullable: true
        homeLoanTotalOutstanding:
            type: integer
            column: home_loan_total_outstanding
            nullable: true
        carLoanMonthlyRepayments:
            type: integer
            column: car_loan_monthly_repayments
            nullable: true
        carLoanTotalOutstanding:
            type: integer
            column: car_loan_total_outstanding
            nullable: true
        personalLoanMonthlyRepayments:
            type: integer
            column: personal_loan_monthly_repayments
            nullable: true
        personalLoanTotalOutstanding:
            type: integer
            column: personal_loan_total_outstanding
            nullable: true
        otherLoanMonthlyRepayments:
            type: integer
            column: other_loan_monthly_repayments
            nullable: true
        otherLoanTotalOutstanding:
            type: integer
            column: other_loan_total_outstanding
            nullable: true

        userID:
            type: integer
            column: user_id
            nullable: true

    oneToOne:
        user:
            targetEntity: UserBundle\Entity\User
            inversedBy: survey
            joinColumn:
                name: user_id
                referencedColumnName: id

    oneToMany:
        creditcards:
            targetEntity: ExampleBundle\Entity\Creditcards
            mappedBy: survey
    lifecycleCallbacks: {  }

这是我的survey实体

use Doctrine\ORM\Mapping as ORM;
use UserBundle\Entity\User;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * survey
 */
class survey
{
    /**
     * @var integer
     */
    private $id;     

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


    /**
     * Set homeLoanMonthlyRepayments
     *
     * @param integer $homeLoanMonthlyRepayments
     * @return survey
     */
    public function setHomeLoanMonthlyRepayments($homeLoanMonthlyRepayments)
    {
        $this->homeLoanMonthlyRepayments = $homeLoanMonthlyRepayments;

        return $this;
    }

    /**
     * Get homeLoanMonthlyRepayments
     *
     * @return integer 
     */
    public function getHomeLoanMonthlyRepayments()
    {
        return $this->homeLoanMonthlyRepayments;
    }

    /**
     * Set homeLoanTotalOutstanding
     *
     * @param integer $homeLoanTotalOutstanding
     * @return survey
     */
    public function setHomeLoanTotalOutstanding($homeLoanTotalOutstanding)
    {
        $this->homeLoanTotalOutstanding = $homeLoanTotalOutstanding;

        return $this;
    }

    /**
     * Get homeLoanTotalOutstanding
     *
     * @return integer 
     */
    public function getHomeLoanTotalOutstanding()
    {
        return $this->homeLoanTotalOutstanding;
    }

    /**
     * Set carLoanMonthlyRepayments
     *
     * @param integer $carLoanMonthlyRepayments
     * @return survey
     */
    public function setCarLoanMonthlyRepayments($carLoanMonthlyRepayments)
    {
        $this->carLoanMonthlyRepayments = $carLoanMonthlyRepayments;

        return $this;
    }

    /**
     * Get carLoanMonthlyRepayments
     *
     * @return integer 
     */
    public function getCarLoanMonthlyRepayments()
    {
        return $this->carLoanMonthlyRepayments;
    }

    /**
     * Set carLoanTotalOutstanding
     *
     * @param integer $carLoanTotalOutstanding
     * @return survey
     */
    public function setCarLoanTotalOutstanding($carLoanTotalOutstanding)
    {
        $this->carLoanTotalOutstanding = $carLoanTotalOutstanding;

        return $this;
    }

    /**
     * Get carLoanTotalOutstanding
     *
     * @return integer 
     */
    public function getCarLoanTotalOutstanding()
    {
        return $this->carLoanTotalOutstanding;
    }

    /**
     * Set personalLoanMonthlyRepayments
     *
     * @param integer $personalLoanMonthlyRepayments
     * @return survey
     */
    public function setPersonalLoanMonthlyRepayments($personalLoanMonthlyRepayments)
    {
        $this->personalLoanMonthlyRepayments = $personalLoanMonthlyRepayments;

        return $this;
    }

    /**
     * Get personalLoanMonthlyRepayments
     *
     * @return integer 
     */
    public function getPersonalLoanMonthlyRepayments()
    {
        return $this->personalLoanMonthlyRepayments;
    }

    /**
     * Set personalLoanTotalOutstanding
     *
     * @param integer $personalLoanTotalOutstanding
     * @return survey
     */
    public function setPersonalLoanTotalOutstanding($personalLoanTotalOutstanding)
    {
        $this->personalLoanTotalOutstanding = $personalLoanTotalOutstanding;

        return $this;
    }

    /**
     * Get personalLoanTotalOutstanding
     *
     * @return integer 
     */
    public function getPersonalLoanTotalOutstanding()
    {
        return $this->personalLoanTotalOutstanding;
    }

    /**
     * Set otherLoanMonthlyRepayments
     *
     * @param integer $otherLoanMonthlyRepayments
     * @return survey
     */
    public function setOtherLoanMonthlyRepayments($otherLoanMonthlyRepayments)
    {
        $this->otherLoanMonthlyRepayments = $otherLoanMonthlyRepayments;

        return $this;
    }

    /**
     * Get otherLoanMonthlyRepayments
     *
     * @return integer 
     */
    public function getOtherLoanMonthlyRepayments()
    {
        return $this->otherLoanMonthlyRepayments;
    }

    /**
     * Set otherLoanTotalOutstanding
     *
     * @param integer $otherLoanTotalOutstanding
     * @return survey
     */
    public function setOtherLoanTotalOutstanding($otherLoanTotalOutstanding)
    {
        $this->otherLoanTotalOutstanding = $otherLoanTotalOutstanding;

        return $this;
    }

    /**
     * Get otherLoanTotalOutstanding
     *
     * @return integer 
     */
    public function getOtherLoanTotalOutstanding()
    {
        return $this->otherLoanTotalOutstanding;
    }

    /**
     * @var integer
     */
    private $userID;


    /**
     * Set userID
     *
     * @param integer $userID
     * @return survey
     */
    public function setUserID($userID)
    {
        $this->userID = $userID;

        return $this;
    }

    /**
     * Get userID
     *
     * @return integer
     */
    public function getUserID()
    {
        return $this->userID;
    }
    /**
     * @var \UserBundle\Entity\User
     */
    private $user;

    /**
     * @var \ExampletBundle\Entity\Creditcards
     */
    private $creditcards;


    /**
     * Set user
     *
     * @param \UserBundle\Entity\User $user
     * @return survey
     */
    public function setUser(User $user)
    {
        $this->user = $user;

        return $this;
    }

    /**
     * Get user
     *
     * @return \UserBundle\Entity\User 
     */
    public function getUser()
    {
        return $this->user;
    }

    public function __toString()
    {
        return (string) $this->getUser();
    }

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->creditcards = new ArrayCollection();
    }

    /**
     * Add creditcards
     *
     * @param \ExampletBundle\Entity\Creditcards $creditcards
     * @return survey
     */
    public function addCreditcard(\ExampleBundle\Entity\Creditcards $creditcards)
    {
        if (!$this->creditcards->contains($creditcards)) {
            $this->creditcards->add($creditcards);
        }
        return $this;
    }

    /**
     * Remove creditcards
     *
     * @param \ExampletBundle\Entity\Creditcards $creditcards
     */
    public function removeCreditcard(\ExampleBundle\Entity\Creditcards $creditcards)
    {
        $this->creditcards->removeElement($creditcards);
    }

    /**
     * Get creditcards
     *
     * @return \Doctrine\Common\Collections\Collection 
     */
    public function getCreditcards()
    {
        return $this->creditcards;
    }
}

在控制器中调用并传递给树枝的表单

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;


class debtType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('homeLoanMonthlyRepayments')
            ->add('homeLoanTotalOutstanding')
            ->add('carLoanMonthlyRepayments')
            ->add('carLoanTotalOutstanding')
            ->add('personalLoanMonthlyRepayments')
            ->add('personalLoanTotalOutstanding')
            ->add('otherLoanMonthlyRepayments')
            ->add('otherLoanTotalOutstanding')            
            ->add('creditcards', 'collection', array('type' => new CreditcardsType(), 'allow_add' => true, 'by_reference' => false,
            ));

    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)    {
        $resolver->setDefaults(array(
            'data_class' => 'ExampleBundle\Entity\survey'
        ));
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'examplebundle_debt';
    }
}

最后我的debtAction处理表单并尝试保存数据

public function debtAction(Request $request){
    $em = $this->getDoctrine()->getManager();
    //get user id of currently logged in user
    $userId = $this->getUser()->getId();

    //get survey object of currently logged in user
    $userExpensesInfo = $em->getRepository('ExampleBundle:survey')->findOneByuserID($userId);
   $form = $this->createForm(new debtType(), $userExpensesInfo);
    $form->handleRequest($request);

    if($request->isMethod('POST')){
        if($form->isValid()){
            $userExpensesInfo->setExpenseFood($form->get('homeLoanMonthlyRepayments')->getData());
            $userExpensesInfo->setExpenseFood($form->get('homeLoanTotalOutstanding')->getData());
            $userExpensesInfo->setExpenseHousing($form->get('carLoanMonthlyRepayments')->getData());
            $userExpensesInfo->setExpenseTransport($form->get('carLoanTotalOutstanding')->getData());
            $userExpensesInfo->setExpenseFun($form->get('personalLoanMonthlyRepayments')->getData());
            $userExpensesInfo->setExpenseClothing($form->get('personalLoanTotalOutstanding')->getData());
            $userExpensesInfo->setExpenseUtil($form->get('otherLoanMonthlyRepayments')->getData());
            $userExpensesInfo->setExpensePersonal($form->get('otherLoanTotalOutstanding')->getData());
            $userExpensesInfo->getCreditcards()->add($form->get('creditcards')->getData());                
            $em->flush();
            $this->get('session')->getFlashBag()->add(
                'notice',
                'Your loan information has been saved'
            );
            return $this->render('ExampleBundle:Default/dashboard:debt.html.twig', array(
                'form'=>$form->createView(),
            ));
        }
    }
    return $this->render('ExampleBundle:Default/dashboard:debt.html.twig', array(
        'form'=>$form->createView(),
    ));
}

我已逐步完成了this文章,但我无法让保存工作,当我尝试保存时,这就是我得到的错误

A new entity was found through the relationship 'ExampleBundle\Entity\survey#creditcards' that was not configured to cascade persist operations for entity: ExampleBundle\Entity\Creditcards@000000001bbd76da000000008bbf1e28. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example @ManyToOne(..,cascade={"persist"}). If you cannot find out which entity causes the problem implement 'ExampleBundle\Entity\Creditcards#__toString()' to get a clue.
500 Internal Server Error - ORMInvalidArgumentException

我在上面评论过的文章确实在this部分谈到了它,我遵循了指令,无论我做什么,我都无法通过这个错误。现在已经超过6个小时了,我正在努力解决这个问题,我不能再思考了。

如果我能在这里得到一些,我将非常感激。

更新:

imports:
    - { resource: parameters.yml }
    - { resource: security.yml }
    - { resource: services.yml }

# Put parameters here that don't need to change on each machine where the app is deployed
# http://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
    locale: en

framework:
    #esi:             ~
    translator:      { fallbacks: ["%locale%"] }
    secret:          "%secret%"
    router:
        resource: "%kernel.root_dir%/config/routing.yml"
        strict_requirements: ~
    form:            ~
    csrf_protection: ~
    validation:      { enable_annotations: true }
    #serializer:      { enable_annotations: true }
    templating:
        engines: ['twig']
        #assets_version: SomeVersionScheme
    default_locale:  "%locale%"
    trusted_hosts:   ~
    trusted_proxies: ~
    session:
        # handler_id set to null will use default session handler from php.ini
        handler_id:  ~
    fragments:       ~
    http_method_override: true

# Twig Configuration
twig:
    debug:            "%kernel.debug%"
    strict_variables: "%kernel.debug%"

# Assetic Configuration
assetic:
    debug:          "%kernel.debug%"
    use_controller: false
    bundles:        [ ExampleBundle ]
    #java: /usr/bin/java
    filters:
        cssrewrite: ~
        #closure:
        #    jar: "%kernel.root_dir%/Resources/java/compiler.jar"
        #yui_css:
        #    jar: "%kernel.root_dir%/Resources/java/yuicompressor-2.4.7.jar"

# Doctrine Configuration
doctrine:
    dbal:
        driver:   pdo_mysql
        host:     "%database_host%"
        port:     "%database_port%"
        dbname:   "%database_name%"
        user:     "%database_user%"
        password: "%database_password%"
        charset:  UTF8
        # if using pdo_sqlite as your database driver:
        #   1. add the path in parameters.yml
        #     e.g. database_path: "%kernel.root_dir%/data/data.db3"
        #   2. Uncomment database_path in parameters.yml.dist
        #   3. Uncomment next line:
        #     path:     "%database_path%"

    orm:
        auto_generate_proxy_classes: "%kernel.debug%"
        naming_strategy: doctrine.orm.naming_strategy.underscore
        auto_mapping: true

# Swiftmailer Configuration
swiftmailer:
    transport: "%mailer_transport%"
    host:      "%mailer_host%"
    username:  "%mailer_user%"
    password:  "%mailer_password%"
    spool:     { type: memory }

3 个答案:

答案 0 :(得分:0)

您需要将cascade: ["persist"]添加到调查名单中的oneToMany映射中。

顺便说一句:类名应该是单数和大写的。

答案 1 :(得分:0)

您想要实现的目标(在检查之后)是双向的多对多关联,如文档的第5.9章所示:http://doctrine-orm.readthedocs.org/en/latest/reference/association-mapping.html

确保正确定义您的“拥有”方面,并根据它设置并保留关联的两边(请参阅上面链接中的5.9.1) - 否则您的实体无法正确保留。

如果您只需要在提供的文档中进行单向多对多检查5.8。

答案 2 :(得分:0)

我终于开始工作了。我似乎没有正确使用Symfony保存信用卡详细信息。

在我的控制器内部,我手动设置数据,这在我的情况下完全不需要

$userExpensesInfo->setExpenseFood($form->get('homeLoanMonthlyRepayments')->getData());
$userExpensesInfo->setExpenseFood($form->get('homeLoanTotalOutstanding')->getData());
$userExpensesInfo->setExpenseHousing($form->get('carLoanMonthlyRepayments')->getData());
$userExpensesInfo->setExpenseTransport($form->get('carLoanTotalOutstanding')->getData());
$userExpensesInfo->setExpenseFun($form->get('personalLoanMonthlyRepayments')->getData());
$userExpensesInfo->setExpenseClothing($form->get('personalLoanTotalOutstanding')->getData());
$userExpensesInfo->setExpenseUtil($form->get('otherLoanMonthlyRepayments')->getData());
$userExpensesInfo->setExpensePersonal($form->get('otherLoanTotalOutstanding')->getData()); $userExpensesInfo->getCreditcards()->add($form->get('creditcards')->getData());       

然后我必须将我的功能addCreditCard更改为以下

public function addCreditCard(CreditCard $card)
{
    if (!$this->creditcards->contains($card)) {
        $this->creditcards->add($card);
    }
    $card->setSurvey($this);
}         

之后它完全正常工作。