【问题标题】:Laravel doctrine2 many to many relation with extra columnLaravel教义2与额外列的多对多关系
【发布时间】:2018-07-19 05:57:48
【问题描述】:

所以当涉及到一个项目的多对多关系时,我开始与 Doctrine2 斗争,其中关系有 1 个额外的列。

我有以下表格:

  • 个人资料
    • 身份证
    • 额外数据
  • 技能

    • 身份证
    • 姓名
  • profile_has_skills

    • profile_id
    • skill_id
    • 级别

现在我稍后添加了级别列,并注意到发生了一些问题,当然,当我尝试创建关系时,我现在缺少级别。 我的问题是,使用下面的代码,我将如何在我的学说中添加它?

我的控制器:

public function store(Request $request)
{
    $time = new DateTime();

    $this->validate($request, [
        'name' => 'required',
        'lastname' => 'required',
        'gender' => 'required',
        'profile_skills' => 'required'
    ]);

    $this->em->getConnection()->beginTransaction();

    try {
        $profile = new Profile(
            $request->input('company_id'),
            $request->input('name'),
            $request->input('lastname'),
            $request->input('gender'),
            new DateTime(),
            $time,
            $time
        );

        $company = $this->em->getRepository(Company::class)->find($request->input('company_id'));
        $profile->addCompany($company);

        foreach($request->input('profile_skills') as $skill => $level) {
            $skill = $this->em->getRepository(Skill::class)->find($skill);
            $skill->level = $level;
            $profile->addSkill($skill);
        }

        $this->em->persist($profile);
        $this->em->flush();
        $this->em->getConnection()->commit();

    } catch (OptimisticLockException $e) {

        $this->em->getConnection()->rollBack();

        throw $e;
    }

    return redirect(route('profiles.index'));
}

我的 ProfileHasSkill 实体如下所示:

/**
 * @ORM\Entity
 * @ORM\Table(name="profile_has_skill")
 *
 */
class ProfileHasSkill
{
/**
 * @ORM\Id
 * @ORM\GeneratedValue
 * @ORM\Column(type="integer")
 */
protected $id;

/**
 * @Column(type="integer", name="profile_id")
 */
protected $profile_id;


/**
 * @Column(type="integer", name="skill_id")
 */
protected $skill_id;

/**
 * @Column(type="integer", name="level")
 */
protected $level;

/**
 * @param $profile_id
 * @param $skill_id
 * @param $level
 */
public function __construct($profile_id, $skill_id, $level = 0)
{
    $this->profile_id = $profile_id;
    $this->skill_id = $skill_id;
    $this->level = $level;
}

我在个人资料实体中的 addSkill 方法如下:

public function addSkill(Skill $skill)
{
    if ($this->skills->contains($skill)) {
        return;
    }
    return $this->skills->add($skill);
}

但每当我尝试运行它时,都会出现以下错误

An exception occurred while executing 
'INSERT INTO profile_has_skill (profile_id, skill_id) VALUES (?, ?)' 
with params [3, 2]: SQLSTATE[HY000]: General error: 1364 Field 'level' 
doesn't have a default value

现在我知道摆脱这个错误的一种方法是在数据库中设置一个默认值,但我更愿意找出为什么它没有提高我也通过的技能水平?

【问题讨论】:

    标签: php laravel doctrine-orm many-to-many entity-relationship


    【解决方案1】:

    具有多对多关系的事情是,两个表中除了两个主键之外的任何其他列都被视为 pivot 列,当您将实体附加到此类关系时,您要使用方法 attach 接受 id 数组作为第一个参数和一个带有 pivot 列的数组,请考虑以下因素。

    public function addSkill(Skill $skill)
    {
        if ($this->skills->contains($skill)) {
            return;
        }
        //Dunno what this method does
        return $this->skills->add($skill);
        //But this is the correct way of adding a skill
        $this->skills->attach($skill->id, ['level' => $skill->level]);
    }
    

    希望这可以澄清一些事情,即使以 Eloquent 为例; here is the manual link 以上代码。

    【讨论】:

    • 我试过这个,但遗憾的是教义2没有附加方法,问题是教义2是在大型数据库上更快速度的要求,因此我不能使用Eloquent :(,add方法也是一个将自动填充 profile_has_skills 表的学说方法,但它缺少“级别”参数,这很奇怪,因为我在控制器中添加了级别,或者至少我是这么认为的
    • 我刚刚偶然发现stackoverflow.com/questions/15616157/…,这意味着您的 profile_has_skills 实体将无法拥有额外的字段,在这种情况下是水平的,我错了吗?
    • 啊,真可惜!不过,我想我必须在教义中添加自己的功能才能实现这一点。
    • 没错,我认为这对 Doctrine 来说是一个很大的缺点,但是,祝你好运:D
    • 我找到了一个可行的解决方案,如果有兴趣,您可以在上面阅读。
    【解决方案2】:

    根据我的解决方案,通过阅读@Nicola Havric - Read as follow 传递的另一个问题,该学说不支持多对多关系中的额外列。因此,您应该使用关系作为它自己的实体。我自己的解决方案是改变我希望它通过冲洗运行的方式。

    在我的控制器中,我将代码更改如下:

    try {
        $profile = new Profile(
            $request->input('company_id'),
            $request->input('name'),
            $request->input('lastname'),
            $request->input('gender'),
            new DateTime(),
            $time,
            $time
        );
    
        $company = $this->em->getRepository(Company::class)->find($request->input('company_id'));
        $profile->addCompany($company);
        //Flush the user, so I can grab it's profile ID
        $this->em->persist($profile);
        $this->em->flush();
    
        foreach($request->input('profile_skills') as $skill => $level) {
            $skill = $this->em->getRepository(Skill::class)->find($skill);
            $skill->level = $level;
            $profile->addSkill($skill);
        }
    
    
        $this->em->getConnection()->commit();
    

    在我的 Profile Entity 函数中:

    public function addSkill(Skill $skill)
    {
        //I left this check since it only checks if the relation is set already. If so, it will skip it.
        if ($this->skills->contains($skill)) {
            return;
        }
    
        //Since this function gets called inside a loop, I can call the entity to add a new "relation" to the table.
        (new ProfileHasSkill($this->getId(), $skill, $skill->level))->addSkill($this->getId(), $skill, $skill->level);
    
        return true;
    }
    

    在我的 ProfileHasSkill 实体中:

     public function addSkill($profileId, $skill)
    {
        //Creating a new ProfileHasSkill inside the table.
        $profileSkill = new ProfileHasSkill(
            $profileId,
            $skill->getId(),
            $skill->level
        );
    
        /*Since I do a roll-back inside my controller in case something goes wrong.
           I decided to add the flush here. 
           As far no additional checks where needed in my case 
           since I require a Profile instance and a Skill instance inside the Profile entity.*/
        EntityManager::persist($profileSkill);
        EntityManager::flush();
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-02-02
      • 1970-01-01
      • 2013-11-14
      • 2014-09-30
      • 1970-01-01
      • 1970-01-01
      • 2017-11-22
      相关资源
      最近更新 更多