0

I want to Use firstOrCreate Function of Eloquent. The relevant part of my Data are Athletes belonging to a Nation and Nation holding many Athletes. (One to Many Relation)

class Athlete extends Model
{
  public $timestamps = false;
  protected $fillable = ['firstname', 'lastname', 'nation'];
.....
  public function nation()
  {
      return $this->belongsTo('App\Nation');
  }
}

and

class Nation extends Model
{
  public $timestamps = false;
...
  public function athletes()
  {
      return $this->hasMany('App\Athlete');
  }
}

How can I use firstOrCreate if I also have to check for the nation?

Neither

$ath = Athlete::firstOrCreate(['nation_id'=>$nation->id, 'lastname'=>$nn, 'sex'=>$sex, 'firstname'=>$vn] );

nor

$ath = Athlete::firstOrCreate(['nation'=>$nation, 'lastname'=>$nn, 'sex'=>$sex, 'firstname'=>$vn] );

work.

First case:

"Nation_id doesn't have a default value"

Second case:

Laravel tries to build a WHERE statement with the passed object, which obviously doesn't work.

Can I use firstOrCreate here?

THANK YOU.

MLavoie
  • 9,671
  • 41
  • 36
  • 56
gnarf
  • 11
  • 5
  • Possible duplicate of [Laravel Eloquent - firstOrCreate() on a relationship](https://stackoverflow.com/questions/23965615/laravel-eloquent-firstorcreate-on-a-relationship) – pspatel May 30 '18 at 09:48
  • no, i checked that before, but that's a different question. My question is how to check a relation within the firstOrCreate method, the linked question is How to use the findOrCreate method via a relation. – gnarf May 30 '18 at 12:47

2 Answers2

1

First in the $fillable protected field you have underlined a nation field related to DB. According to this i don't understand the field nation_id in the second attempt query.

In the declaration of relation please underline the external key so that the difference between the two fields (nation and nation_id) becomes clear.

Assuming that the field nation contains the relation to Nations' record (matching relation on primary unique ID), you are able to compare provided data on this ID (for nation comparison) and not on all nation fields.

Then the first case that you have reported I supposed is wrong

First case: "Nation_id doesn't have a default value"

because this means that you are inserting an athlete without providing a nation id and the conseguence is that this id isn't checked in query builder (probably because is null). In this way you not reveals comparison with the current athlete and the existing db athlete if nation is null.

In general i suggest you to do this steps to complete your task:

  1. Check if all data passed to query builder is correctly
  2. Write the query in this way

    $ath = Athlete::firstOrCreate(['field_that_contains_nation_id'=>$nation->id, 'other_athlete_fields' => $value, ...] );
    

    then run operation for this Model

    $ath->save();
    

    if you want know if the record is created done this:

    if($ath->wasRecentlyCreated){
        echo 'Created successfully';
    } else {
        echo 'Already exist';
    }
    

If already this not work please check that the relations is setting properly within the tables.

Matteo Conti
  • 11
  • 1
  • 4
  • I use standard Laravel naming (i hope) the related object is called "nation". So Laravel uses the mysql column "nation_id" as foreign key. In the $nation variable i have the Object, so i tried (as you suggested) to compare the IDs. (My first example in the original question) What you you mean with proper relation setting? In my models i have the relations (see original question). In the mysql tables i have a "id" field in both tables, and a "nation_id" as foreign key. All Laravel standard naming. I do not use a mysql relation, because the relation should be handled by laravel. – gnarf May 30 '18 at 12:45
  • yes don't use the sql relation but with check that the relations is setting properly within the tables I mean this: 1. declare explicitly the key where laravel set the relation return $this->hasOne('App\Athlete', 'foreign_key'); 2. first try to separate the step which are done by the FirstOrCreate function by creating a select query to find the number of row equals to input data and then insert query if this count is 0. This allow you to verify that Laravel recognize correctly the relation. – Matteo Conti May 31 '18 at 08:11
1

$fillable has to contain the column name, not the relation name. Also, sex is missing:

protected $fillable = ['firstname', 'lastname', 'sex', 'nation_id'];
Jonas Staudenmeir
  • 24,815
  • 6
  • 63
  • 109