Eloquent hasOne Relationship即使存在相关记录也会返回NULL

问题描述 投票:0回答:4

我有一个小练习会计应用程序,我正在使用Laravel来提供REST api。我试图使用雄辩的关系来处理交付对象,包括他们的关系。

现在我有一个“交易”模型,如下所示。

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();

此查询返回如下所示的结果,其中第一个结果返回关系,但每个后续记录都为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,所以这些记录根本不应该为null。

我试图理解为什么会发生这种情况,我看起来很高低,但我找不到解释。我在下面列出了一个屏幕截图,指出了MySQL中表格的记录。

enter image description here

php mysql laravel-5 eloquent
4个回答
1
投票

我找到了问题的解决方案,它与IzzEps指出的方向相同。

我最初建立关系的方式是这样的。

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

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

我又看了一眼eloquent relationship docs,发现了这个:

此外,Eloquent假定外键应具有与父级的id(或自定义$ primaryKey)列匹配的值。换句话说,Eloquent将在电话记录的user_id列中查找用户id列的值。如果您希望关系使用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”是“transaction”表的“本地”键或者“local_key”中的键。文档。

我没有完全指定如何定义关系以及关系应该使用哪些键。谢谢你指出我正确的方向,应该是第二性质,回到文档。

因此,一如既往,我应该更密切地RTM。


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_idtransaction_status_id的正确外键相对)。结果是,在调用Transaction::with("TransactionType", "TransactionStatus")时,您将在错误的外键(transaction_type)上加入transaction_statustransaction.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
投票

没有第一次看到它。实际上你在你的`交易模型上存储了transaction_type_idtransaction_status_id。这实质上意味着关系应该被定义为

  Transaction belongsTo TransactionType  &  (Inverse) TransactionType hasMany Transaction

  Transaction belongsTo TransactionStatus  & (Inverse) TransactionStatus hasMany Transaction  

hasOnebelongsTohasMany的签名非常不同。

所以应该定义关系(根据您当前的代码)

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();  

应该为您返回所需的输出。没有测试过,但绝对应该工作。

希望这可以帮助。如果不是,请告诉我。


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

我设法得到这样的。我们应该使用local_key作为列名来工作。

© www.soinside.com 2019 - 2024. All rights reserved.