Eloquent hasOne Relationship Returns NULL even when related records exist

laravel eloquent one to many example
laravel one to many relationship with pivot table
must return a relationship instance, but null'' was returned was the return'' keyword used
laravel eloquent join
laravel hasmanythrough example
laravel eloquent relationships tutorial
polymorphic relationship
with in laravel query

I have a small practice accounting app that I'm building using Laravel to provide a REST api. I am trying to use eloquent relationships to handle delivering objects including their relations.

Right now I have a "Transaction" model which looks like the following.

class Transaction extends Model
{
  protected $table = "transaction";

  protected $fillable = [
    "transaction_type_id",
    "account_id",
    "description",
    "amount",
    "comments",
    "transaction_status_id",
    "posting_date"
  ];

  protected $guarded = [
    "id"
  ];

  public static function create(array $attributes = Array()) {

    $account = BankAccount::find($attributes["account_id"]);

    if ($attributes["transaction_type_id"] == 1) {
        //Credit
        $account["balance"] += $attributes["amount"];
    } else if ($attributes["transaction_type_id"] == 2) {
        //Debit
        $account["balance"] -= $attributes["amount"];
    }

    $account->save();
    parent::create($attributes);    
  }

  public function transactionType() {
    return $this->hasOne("App\Model\TransactionType", "id");
  }

  public function transactionStatus() {
    return $this->hasOne("App\Model\TransactionStatus", "id");
  }
}

The TransactionStatus model looks like this

class TransactionStatus extends Model
{
  protected $table = "transaction_status";

  protected $guarded = [
      "id", "description"
  ];
}

And the TransactionType model looks like this

class TransactionType extends Model
{
  protected $table = "transaction_type";

  protected $guarded = [
    "id", "description"
  ];
}

I have the following in my controller

return Transaction::with("TransactionType", "TransactionStatus")
    ->where("account_id", $accountId)
    ->get()
    ->toJson();

This query returns a result that looks like the following, where the first result returns the relation, but every subsequent record has null.

  {
   "id": 1,
   "transaction_type_id": 1,
   "account_id": 1,
   "description": "Morbi metus. Vivamus euismod urna.",
   "amount": "4179.00",
   "comments": "ullamcorper, nisl arcu iaculis enim,",
   "transaction_status_id": 1,
   "posting_date": "2016-12-10 21:24:25",
   "created_at": "2016-12-10 00:00:00",
   "updated_at": "2016-12-10 00:00:00",
   "transaction_type": {
     "id": 1,
     "description": "Credit",
     "created_at": "2016-12-09 13:37:00",
     "updated_at": "2016-12-09 13:37:00"
  },
  "transaction_status": {
    "id": 1,
    "description": "Pending",
    "created_at": "2016-12-09 13:37:00",
    "updated_at": "2016-12-09 13:37:00"
  }
 },
 {
  "id": 3,
  "transaction_type_id": 1,
  "account_id": 1,
  "description": "lorem ut aliquam iaculis, lacus",
  "amount": "2710.00",
  "comments": "ac, eleifend vitae, erat. Vivamus",
  "transaction_status_id": 1,
  "posting_date": "2016-07-16 04:23:34",
  "created_at": "2016-12-10 00:00:00",
  "updated_at": "2016-12-10 00:00:00",
  "transaction_type": null,
  "transaction_status": null
 }

The above result makes no sense to me because all of the records in the transaction table have both a transaction_type_id and a transaction_status_id, so these shouldn't be null at all.

I've looked high and low trying to understand why this might happen, but I've not been able to find an explanation. I've included a screenshot below that indicates how the records look in the table in MySQL as well.

I found the solution to the problem and it was along the same lines of what IzzEps pointed out.

The way that I had the relationships originally set up is like this.

public function transactionType() {
  return $this->hasOne("App\Model\TransactionType", "id");
}

public function transactionStatus() {
  return $this->hasOne("App\Model\TransactionStatus", "id");
}

I took another look at the eloquent relationship docs and found this:

Additionally, Eloquent assumes that the foreign key should have a value matching the id (or the custom $primaryKey) column of the parent. In other words, Eloquent will look for the value of the user's id column in the user_id column of the Phone record. If you would like the relationship to use a value other than id, you may pass a third argument to the hasOne method specifying your custom key: return $this->hasOne('App\Phone', 'foreign_key', 'local_key');

When I changed the relationships to this:

public function transactionType() {
    return $this->hasOne("App\Model\TransactionType", "id", "transaction_type_id");
}

public function transactionStatus() {
    return $this->hasOne("App\Model\TransactionStatus", "id", "transaction_status_id");
}

I got the results I was expecting. In this case "id" is the foreign key which exists on the transaction_status or transaction_type table, and "transaction_type_id" or "transaction_status_id" is the key that is "local" to the "transaction" table or the "local_key" in the parlance of the docs.

I was not fully specifying how the relationships are defined and what keys the relationships should be using. Thanks for pointing me in the right direction which, as should be second-nature, was back to the documentation.

So, as always, I should more closely RTM.

Check if Eloquent Relationship is Empty, The media_profile table has a FK pointing to the User record it belongs to. This should be all that you need to do, since non-existent relations return null. even if the Collection is empty is_null() will always return false use @BenderIsGreat , @tag sorry for inconvenience, didn't see the hasOne relation. The belongsTo, hasOne, hasOneThrough, and morphOne relationships allow you to define a default model that will be returned if the given relationship is null. This pattern is often referred to as the Null Object pattern and can help remove conditional checks in your code.

When defining the following relationships

public function transactionType() {
    return $this->hasOne("App\Model\TransactionType", "id");
}

public function transactionStatus() {
   return $this->hasOne("App\Model\TransactionStatus", "id");
}

you are specifying the id of the Transaction model table as the foreign key for both of these relationships (as opposed to the correct correct foreign key's of transaction_type_id and transaction_status_id respectively). The result is that when calling Transaction::with("TransactionType", "TransactionStatus") you are joining both the transaction_type and transaction_status table on the wrong foreign key (transaction.id).

To Fix:

Simply update your relationships to use the correct foreign keys as follows:

public function transactionType() {
    return $this->hasOne("App\Model\TransactionType", "transaction_type_id");
}

public function transactionStatus() {
   return $this->hasOne("App\Model\TransactionStatus", "transaction_status_id");
}

Hope this helps...

Eloquent Relationship Returns Null When Using Query Scope, Eloquent Relationship Returns Null When Using Query Scope return $this-> hasOne(MarkedLessonCompleteEvent::class, 'user_id', 'id') scope that is causing certain relations to return null when a valid record exists? The belongsTo, hasOne, hasOneThrough, and morphOne relationships allows us to define a default model that will be returned if the given relationship is null. This pattern is referred to as the Null Object pattern most times and helps remove conditional checks in our code.

Didn't see it the first time. Actually you are storing the transaction_type_id and transaction_status_id on your `Transaction model. Which essentially means that the relation should be defined as

  Transaction belongsTo TransactionType  &  (Inverse) TransactionType hasMany Transaction

and

  Transaction belongsTo TransactionStatus  & (Inverse) TransactionStatus hasMany Transaction  

The signatures of hasOne, belongsTo and hasMany are very different.

So the relationships should be defined (as per your current code)

class Transaction extends Model
{
    protected $table = "transaction";

      protected $fillable = [
        "transaction_type_id",
        "account_id",
        "description",
        "amount",
        "comments",
        "transaction_status_id",
        "posting_date"
      ];

    public function transactionType()
    {
        return $this->belongsTo('App\Model\TransactionType');
    }

    public function transactionStatus()
    {
        return $this->belongsTo('App\Model\TransactionStatus');
    }
}  

class TransactionType extends Model
{

    protected $table = "transaction_types";

    protected $fillable = [ /* mass assignable fields */];

    public function transactions()
    {
        return $this->hasMany('App\Model\Transaction');
    }
}


class TransactionStatus
{

    protected $table = "transaction_statuses";

    protected $fillable = [ /* mass assignable fields */];

    public function transactions()
    {
        return $this->hasMany('App\Model\Transaction');
    }
}  

As per Laravel documentation Eloquent determines the foreign key of the relationship based on the model name.

Since you are following desired convention of naming the foreign key corresponding to the Model names

transaction_type_id <=> TransactionType and transaction_status_id <=> TransactionStatus  

you can omit specifying the foreign key as second argument to the relationship function.

After defining the relationships as above

return Transaction::with('transactionType', 'transactionStatus')
->where("account_id", $accountId)
->get()
->toJson();  

should return the desired output for you. Haven't tested but should definitely work.

Hope this helps. Let me know if otherwise.

Eloquent: Relationships - Laravel, Once the relationship is defined, we may retrieve the related record using We can define the inverse of a hasOne relationship using the belongsTo method: If you need even more power, you may use the whereHas and orWhereHas methods to put To query the existence of MorphTo relationships, you may use the� Related Issues: #1771, #1299, #753 Previous PRs: #1563 Introduction When fetching a model that has a hasOne relation and that relation doesn't exist the relation should be null when serializing the model. Currently it's an empty object {}.

public function dispute() {
    return $this->hasOne('App\PaypalDispute', 'transaction_id', 'transaction_id');
}

I managed to get it like this. We should use the local_key as the column name in order to work.

How to not load NULL relations in Laravel 5 | by Tom Ellis, Some categories (Main/Parent) will have a null parent_id column, so we don't need to load the relation. <?php namespace App @return \Illuminate\Database \Eloquent\Relations\BelongsTo */ It might not even affect you. I have a project where users can have various different services. Each Service has a separate set of information needed. I have 1 users table and then I have 1 table for each service.

Eloquent: Relationships 5.4 Laravel, Once the relationship is defined, we may retrieve the related record using We can define the inverse of a hasOne relationship using the belongsTo method: you to define a default model that will be returned if the given relationship is null . If you need even more power, you may use the whereDoesntHave method to� Eloquent also offers advanced subquery support, which allows you to pull information from related tables in a single query. For example, let's imagine that we have a table of flight destinations and a table of flights to destinations. The flights table contains an arrived_at column which indicates when the flight arrived at the destination.

Eloquent Relationships: The Ultimate Guide – Quick Admin Panel, Eloquent is a powerful Laravel ORM, and it allows to define NULL: deletes parent entry and sets child foreign key entry to NULL As you can see, we have hasOne() method with only one parameter – related model's It gets even more complex – function whereHas() allows you to query the child entries� Hi, this is my first time trying out eloquent relationships. I've looked at multiple tutorials already. I have two tables. Albums and Artists. An Artist can have many Albums.

Relationships, Once the relationship is defined, we may retrieve the related record using the We can define the inverse of a hasOne relationship using the $belongsTo property: you define a default model that will be returned if the given relationship is null . If you need even more power, you may use the whereHas and orWhereHas� Laravel Laravel IDEA SleepingOwl Orchid Сообщество Discord Telegram GitHub Laravel Framework Russian Community Главная Документация Перевод Статьи Пакеты Версия фреймворка: 7.x 5.4 4.2 Прогресс перевода

Comments
  • Just a side note - in your Transaction model you are using $fillable as well as $guarded, you either $fillable or $guarded should not use both.
  • @Donkarnash, Good catch, the docs specified that and I had neglected to remove the $guarded declaration. Thanks!
  • You are getting the results for the relationships from the Transaction model because you are providing the foreign_key and local_key. How would you define the inverse relations i.e. how would you define the relation from TransactionStatus and TransactionType models? Logically a particular TransactionType (debit or credit) will have many Transaction(s) and same way TransactionStatus (maybe pending or approved) will have many Transaction(s) so the relations should be defined as Many-To-One from Transaction model.
  • I just saw your answer a few moments ago and it makes a lot of sense. I'm going to try that and see if it works.
  • Were you able to accomplish what you were aiming to?
  • Thanks. I managed to get it like this. public function dispute() { return $this->hasOne('App\PaypalDispute', 'transaction_id', 'transaction_id'); }
  • Or you can leave out the foreignkey from relation definition as table name and foreign key naming are following the same convention.
  • This method seemed to me to be the correct way to do this initially as well, the problem is that I got internal server errors when specifying foreign keys like "transaction_type_id" and "transaction_status_id". See the following: "QueryException: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'transaction_type.transaction_type_id' in 'where clause' (SQL: select * from transaction_type where transaction_type.transaction_type_id in (1, 3, 6, 7...,etc."