我有两张桌子,货物和客户。在现实世界中,客户可以通过三种方式与货物相关:作为票据,目的地和/或来源。
所以我的问题是,我是否有一个包含三列的数据透视表,一个用于shipment_id,一个用于customer_id,另一个用于relationship_type id?或者我有单独的表?我不确定如何最好地接近这一点,因为它是我遇到过的第一种。
答案 0 :(得分:2)
几周前我遇到了这个问题,我提出了一个解决方案。
假设一个客户可以有不同的关系 出货。
首先,您需要一个新的客户角色模型,显然它的模型将是Relation模型。
第一种方法:您可以通过使用多个数据透视表来解决这个问题,但是这不是一个好的数据库设计。我首先解决了这个问题,但是当谈到数据库时,我意识到它不是最佳选择。
第二种方法:您可以通过将数据透视表定义为模型来解决此问题,但即使我知道它的工作原理和解决方案,我也没有尝试过这种方法。
更好的方法:为三个模型使用一个数据透视表。在这种情况下,您必须在定义关系示例时定义数据透视表:
客户模式:
public function relations()
{
return $this->belongsToMany(Relation::class, 'customer_relation_shippment');
}
关系模型:
public function customers()
{
return $this->belongsToMany(Relation::class, 'customer_relation_shippment');
}
和其他模型一样。
现在假设您要为客户添加关系。 让我们抓住第一个客户和第一批货物,并说我们想要添加一个关系作为一个比尔:
$customer = Customer::first();
$shipment = Shipment::first();
$relation = Relation::where('name','biller')->get();
$customer->relations()->attach($shipment->id, ['relationship_type'=>$relation->id]);
当然只使用一个数据透视表,对于像CRUD这样的模型执行操作会有点复杂,但当涉及数据库设计/优化时,它当然是正确的选择!请注意,我在处理类似的现实世界问题之后得出了这个结论,并且它使用更多的数据库交互变得更快,然后使用多个数据透视。
答案 1 :(得分:0)
以下是我设计项目的方法。
我认为您甚至不需要数据透视表或多对多关系。
注意:为了清晰起见并避免与User
混淆,我将使用Account
来引用您称之为Customer
的内容。最后,您在评论中使用了customer account
。
您的货件与三个不同的实体相关。但是,这些实体由数据库中的相同数据模型表示:Account
模型。
基本的一对多关系就足够了。
帐户可以有很多货件。货件属于一个帐户。
现在,如何添加关系的“类型”?我们不需要数据透视表,只需添加另一个一对多关系。
Account as biller
可能包含多个货件,货件属于biller
个货件。
Account as origin
可能包含多个货件,货件属于origin
个货件。
Account as destination
可能包含多个货件,货件属于origin
个货件。
要解释一下,这是一个示例代码:
我们有三种模式:User
,Account
和Shipment
让我们从架构开始:
Schema::create('accounts', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
Schema::create('shipments', function (Blueprint $table) {
$table->increments('id');
$table->string('from');
$table->string('to');
$table->unsignedInteger('biller_id');
$table->unsignedInteger('origin_id');
$table->unsignedInteger('destination_id');
$table->foreign('biller_id')
->references('id')->on('accounts');
$table->foreign('origin_id')
->references('id')->on('accounts');
$table->foreign('destination_id')
->references('id')->on('accounts');
$table->timestamps();
});
我们有三列引用id
表上的accounts
。
对于模型和关系:
帐户模型:
class Account extends Model
{
public function billerShipments()
{
return $this->hasMany(Shipment::class, 'biller_id');
}
public function originShipments()
{
return $this->hasMany(Shipment::class, 'origin_id');
}
public function destinationShipments()
{
return $this->hasMany(Shipment::class, 'destination_id');
}
public function users()
{
return $this->belongsToMany(User::class);
}
}
货件型号:
class Shipment extends Model
{
public function billerAccount()
{
return $this->belongsTo(Account::class, 'biller_id');
}
public function originAccount()
{
return $this->belongsTo(Account::class, 'origin_id');
}
public function destinationAccount()
{
return $this->belongsTo(Account::class, 'destination_id');
}
}
创建货件的示例
$billerAccount = \App\Account::create(['name' => 'account b']);
$originAccount = \App\Account::create(['name' => 'account a']);
$destinationAccount = \App\Account::create(['name' => 'account c']);
$newShipment = \App\Shipment::create([
'from' => 'city 1',
'to' => 'city 2',
'biller_id' => $billerAccount->id,
'origin_id' => $originAccount->id,
'destination_id' => $destinationAccount->id,
]);
echo $billerAccount->billerShipments()->count(); // 1
echo $originAccount->originShipments()->count(); // 1
echo $destinationAccount->destinationShipments()->count(); // 1
echo $newShipment->billerAccount->name === $billerAccount->name; // 1
echo $newShipment->originAccount->name === $originAccount->name; // 1
echo $newShipment->destinationAccount->name === $destinationAccount->name; // 1
对于帐户 - 用户关系,它可以是多对多或一对多,具体取决于您的要求。