Docs›Banco de dados›Relacionamentos
Banco de dados

Relacionamentos

belongsTo, hasMany, belongsToMany, eager loading com with().

Relacionamentos no MAD são relations Eloquent nativas — métodos no model que retornam um objeto Illuminate\Database\Eloquent\Relations\*. belongsTo para N:1, hasMany para 1:N, belongsToMany para N:N via tabela pivot.

belongsTo — N:1

Exemplo real (App\Models\Iam\User):

use Illuminate\Database\Eloquent\Relations\BelongsTo;

class User extends Authenticatable
{
    public function unit(): BelongsTo
    {
        return $this->belongsTo(Unit::class, 'unit_id');
    }

    public function frontpage(): BelongsTo
    {
        return $this->belongsTo(Program::class, 'frontpage_id');
    }
}
$user = User::find($id);
echo $user->unit->name; // acesso como propriedade — dispara a query na 1ª leitura

hasMany — 1:N

use Illuminate\Database\Eloquent\Relations\HasMany;

class PedidoVenda extends Model
{
    protected $connection = 'business';
    protected $table      = 'pedido_venda';

    public function itens(): HasMany
    {
        return $this->hasMany(PedidoVendaItem::class, 'pedido_venda_id');
    }
}
$pedido = PedidoVenda::find($id);
foreach ($pedido->itens as $item) {
    echo $item->produto_nome;
}

Acessar $pedido->itens como propriedade é lazy — só dispara a query na primeira leitura, depois reusa o resultado já carregado na instância.

belongsToMany — N:N (com pivot)

Exemplo real (App\Models\Iam\User):

use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class User extends Authenticatable
{
    public function groups(): BelongsToMany
    {
        return $this->belongsToMany(Group::class, 'mad_iam_user_group', 'user_id', 'group_id');
    }

    public function roles(): BelongsToMany
    {
        return $this->belongsToMany(Role::class, 'mad_iam_user_role', 'user_id', 'role_id');
    }
}
$user   = User::find($id);
$grupos = $user->groups; // Collection<Group>

// Sincronizar a pivot (substitui o conjunto inteiro)
$user->groups()->sync([1, 2, 3]);

// Anexar/desanexar sem afetar os demais
$user->groups()->attach(4);
$user->groups()->detach(4);

Eager loading — evitando N+1

Cuidado em listagens: acessar $pedido->cliente->nome dentro de um foreach sem pré-carregar dispara uma query adicional por linha. Use with() para carregar a relação em lote antes do loop.

// ❌ N+1 — uma query por pedido da listagem
foreach (PedidoVenda::all() as $p) {
    echo $p->cliente->nome;
}

// ✅ Eager load — 2 queries no total (pedidos + clientes em lote)
$pedidos = PedidoVenda::with('cliente')->get();
foreach ($pedidos as $p) {
    echo $p->cliente->nome;
}

// Múltiplas relações, inclusive aninhadas
$pedidos = PedidoVenda::with(['cliente', 'itens.produto'])->get();

Carregando/sincronizando filhos manualmente

Quando você precisa de controle total (ex.: substituir todos os itens de um pedido):

// Carregar
$itens = $pedido->itens; // ou $pedido->itens()->get() pra encadear filtros

// Substituir — deleta os antigos e insere os novos
DB::connection('business')->transaction(function () use ($pedido, $itensArray) {
    $pedido->itens()->delete();
    $pedido->itens()->createMany($itensArray);
});

Para smart-sync (atualiza existentes, insere novos, remove sumidos — sem apagar e recriar tudo), use <mad-detail-form>, que faz isso automaticamente. Veja Detail-form.

Exemplo completo: pedido com itens

class PedidoVenda extends Model
{
    protected $connection = 'business';
    protected $table      = 'pedido_venda';

    public function itens(): HasMany
    {
        return $this->hasMany(PedidoVendaItem::class, 'pedido_venda_id');
    }

    public function cliente(): BelongsTo
    {
        return $this->belongsTo(Cliente::class, 'cliente_id');
    }

    protected function totalCalculado(): Attribute
    {
        return Attribute::make(
            get: fn () => $this->itens->sum('valor_total')
        );
    }
}

class PedidoVendaItem extends Model
{
    protected $connection = 'business';
    protected $table      = 'pedido_venda_item';

    public function produto(): BelongsTo
    {
        return $this->belongsTo(Produto::class, 'produto_id');
    }
}
$pedido = PedidoVenda::with(['cliente', 'itens.produto'])->find(42);

echo $pedido->cliente->nome;
echo $pedido->total_calculado;

foreach ($pedido->itens as $item) {
    echo $item->produto->nome . ' — R$ ' . $item->valor_total;
}

Próximos