2016-12-11 6 views
0

У меня есть небольшое приложение для учета практики, которое я использую с помощью Laravel для предоставления REST api. Я пытаюсь использовать красноречие отношения для обработки доставки объектов, включая их отношения.Eloquent hasOne Relationship Возвращает NULL, даже если существуют соответствующие записи

Прямо сейчас у меня есть модель «Транзакция», которая выглядит следующим образом.

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"); 
    } 
} 

Модель TransactionStatus выглядит следующим образом

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

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

И модель TransactionType выглядит следующим образом

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

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

У меня есть следующие в моем контроллере

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

Это дие ry возвращает результат, который выглядит следующим образом: первый результат возвращает отношение, но каждая последующая запись имеет значение 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 
} 

Полученный результат не имеет смысла для меня, потому что все записи в таблице транзакций имеют как transaction_type_id и transaction_status_id, поэтому они не должны быть нулевыми на всех.

Я выглядел высоко и низко, пытаясь понять, почему это может произойти, но я не смог найти объяснения. Я включил снимок экрана ниже, который показывает, как записи выглядят в таблице в MySQL.

enter image description here

+0

Просто боковое примечание. В вашей модели транзакций вы используете $ fillable, а также $ guarded, вы либо $ fillable, либо $ guarded не должны использовать оба. – Donkarnash

+0

@Donkarnash, Хорошая ловушка, документы указали, что я и пренебрег удалением $ охраняемой декларации. Благодаря! – morris295

ответ

0

При определении следующие соотношения

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

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

вы указав id в Transaction модели таблицы в качестве внешнего ключа для обоих этих отношений (в отличие от правильно правильно иностранного ключа из transaction_type_id и transaction_status_id соответственно). В результате при вызове Transaction::with("TransactionType", "TransactionStatus") вы соединяете таблицу transaction_type и transaction_status с неправильным внешним ключом (transaction.id).

исправить:

Просто обновить свои отношения, чтобы использовать правильные внешние ключи следующим образом:

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

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

Надеется, что это помогает ...

+0

Или вы можете оставить внешний ключ от определения отношения как имя таблицы, так и имя именования внешнего ключа следуют тому же соглашению. – Donkarnash

+0

Этот метод, казалось, был правильным способом сделать это изначально, проблема в том, что я получил внутренние ошибки сервера при указании внешних ключей, таких как «transaction_type_id» и «transaction_status_id». См. Следующее: «QueryException: SQLSTATE [42S22]: столбец не найден: 1054 Неизвестный столбец« transaction_type.transaction_type_id »в« where clause »(SQL: выберите * из' transaction_type', где 'transaction_type'.'transaction_type_id' в (1, 3, 6, 7 ... и т. Д. » – morris295

0

Я нашел решение этой проблемы и был тем же самым направлением, о котором указывал IzzEps.

То, как я установил отношения, было так.

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

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

Я еще раз посмотрел на eloquent relationship docs и нашел это:

Кроме того, Красноречивый предполагает, что внешний ключ должен иметь значение, соответствующий идентификатор (или заказ $ PrimaryKey) столбец родителя , Другими словами, Eloquent будет искать значение столбца идентификатора пользователя в столбце user_id записи телефона. Если вы хотите, чтобы отношения использовать значение, отличное от идентификатора, вы можете передать третий аргумент метода hasOne указав свой собственный ключ: return $this->hasOne('App\Phone', 'foreign_key', 'local_key');

Когда я изменил отношения к этому:

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"); 
} 

Я получил результаты, которые ожидал. В этом случае «id» - это внешний ключ, который существует в таблице transaction_status или transaction_type, а «transaction_type_id» или «transaction_status_id» - это ключ, который является «локальным» для таблицы «транзакция» или «local_key» на языке документы.

Я не полностью определял, как определяются отношения и какие ключи должны использовать отношения. Спасибо, что указал мне в правильном направлении, которое, как и должно быть второсортного, вернулось к документации.

Так что, как всегда, я должен ближе к RTM.

+0

Вы получаете результаты для отношений из модели Transaction, потому что вы предоставляете foreign_key и local_key. Как бы вы определили обратные отношения, то есть как бы вы определяли отношение из TransactionStatus и моделей TransactionType? Логически определенный тип транзакции (дебет или кредит) будет иметь много транзакций (транзакций), и тот же способ TransactionStatus (возможно, ожидается или одобрен) будет иметь много транзакций (транзакций), поэтому отношения должны быть определены как многоточие, Один из модели транзакции. – Donkarnash

+0

Я только что видел ваш ответ несколько минут назад, и это имеет большой смысл. Я собираюсь попробовать это и посмотреть, оно работает. – morris295

+0

Вы могли выполнить то, к чему вы стремились? – Donkarnash

0

Не видел его в первый раз. На самом деле вы сохраняете transaction_type_id и transaction_status_id на своей модели транзакций. Что по существу означает, что соотношение должно быть определено как

Transaction belongsTo TransactionType & (Inverse) TransactionType hasMany Transaction 

и

Transaction belongsTo TransactionStatus & (Inverse) TransactionStatus hasMany Transaction 

Подписи hasOne, belongsTo и hasMany очень разные.

Так отношения должны быть определены (согласно текущему коду)

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'); 
    } 
} 

Согласно Laravel документации Eloquent определяет внешний ключ отношений на основе имени модели.

Поскольку вы следуете желаемой условности наименования внешнего ключа, соответствующее названию модели

transaction_type_id <=> TransactionType and transaction_status_id <=> TransactionStatus 

вы можете опускаете указать внешний ключ в качестве второго аргумента функции отношения.

После определения отношений, как описано выше

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

должен возвратить желаемый результат для вас. Не тестировали, но должны определенно работать.

Надеюсь, это поможет. Дайте мне знать, если в противном случае.

Смежные вопросы