relaciĆ³n relacional relacion para hasone hasmany framework ejemplos ejemplo datos belongstomany php laravel eloquent

php - relacional - Laravel relaciones recursivas



relacion uno a uno laravel 5 (4)

Así es como puedes usar relaciones recursivas:

public function childrenAccounts() { return $this->hasMany(''Account'', ''act_parent'', ''act_id''); } public function allChildrenAccounts() { return $this->childrenAccounts()->with(''allChildrenAccounts''); }

Entonces:

$account = Account::with(''allChildrenAccounts'')->first(); $account->allChildrenAccounts; // collection of recursively loaded children // each of them having the same collection of children: $account->allChildrenAccounts->first()->allChildrenAccounts; // .. and so on

De esta manera ahorras muchas consultas. Esto ejecutará 1 consulta por cada nivel de anidamiento + 1 consulta adicional.

No puedo garantizar que sea eficiente para sus datos, necesita probarlos definitivamente.

Esto es para cuentas sin hijos:

public function scopeChildless($q) { $q->has(''childrenAccounts'', ''='', 0); }

entonces:

$childlessAccounts = Account::childless()->get();

Estoy trabajando en un proyecto en Laravel . Tengo un modelo de cuenta que puede tener un padre o puede tener hijos, así que tengo mi modelo configurado así:

public function immediateChildAccounts() { return $this->hasMany(''Account'', ''act_parent'', ''act_id''); } public function parentAccount() { return $this->belongsTo(''Account'', ''act_parent'', ''act_id''); }

Esto funciona bien. Lo que quiero hacer es tener a todos los niños en una cuenta determinada. Actualmente, estoy haciendo esto:

public function allChildAccounts() { $childAccounts = $this->immediateChildAccounts; if (empty($childAccounts)) return $childAccounts; foreach ($childAccounts as $child) { $child->load(''immediateChildAccounts''); $childAccounts = $childAccounts->merge($child->allChildAccounts()); } return $childAccounts; }

Esto también funciona, pero tengo que preocuparme si es lento. Este proyecto es la reescritura de un proyecto antiguo que usamos en el trabajo. Tendremos varios miles de cuentas que migraremos a este nuevo proyecto. Para las pocas cuentas de prueba que tengo, este método no plantea problemas de rendimiento.

¿Hay una solución mejor? ¿Debo ejecutar una consulta en bruto? ¿Tiene Laravel algo para manejar esto?

En resumen Lo que quiero hacer, para una cuenta determinada, es obtener cada cuenta de un solo niño y cada uno de sus hijos, y así sucesivamente en una sola lista / colección. Un diagrama:

A -> B -> D |--> C -> E |--> F G -> H

Si ejecuto A-> InstalarCuenta de Niños (), debería obtener {B, C}
Si ejecuto A-> allChildAccounts (), debería obtener {B, D, C, E, F} (el orden no importa)

Una vez más, mi método funciona, pero parece que estoy haciendo demasiadas consultas.

Además, no estoy seguro de si está bien preguntar esto aquí, pero está relacionado. ¿Cómo puedo obtener una lista de todas las cuentas que no incluyen las cuentas secundarias? Así que básicamente lo inverso de ese método anterior. Esto es para que un usuario no intente dar a una cuenta un padre que ya sea hijo. Usando el diagrama de arriba, quiero (en pseudocódigo):

Account :: where (account_id not in (A-> allChildAccounts ())). Entonces obtendría {G, H}

Gracias por cualquier idea


Creo que también he encontrado una solución decente.

class Organization extends Model { public function customers() { return $this->hasMany(Customer::class, ''orgUid'', ''orgUid''); } public function childOrganizations() { return $this->hasMany(Organization::class, ''parentOrgUid'', ''orgUid''); } static function addIdToQuery($query, $org) { $query = $query->orWhere(''id'', $org->id); foreach ($org->childOrganizations as $org) { $query = Organization::addIdToQuery($query, $org); } return $query; } public function recursiveChildOrganizations() { $query = $this->childOrganizations(); $query = Organization::addIdToQuery($query, $this); return $query; } public function recursiveCustomers() { $query = $this->customers(); $childOrgUids = $this->recursiveChildOrganizations()->pluck(''orgUid''); return $query->orWhereIn(''orgUid'', $childOrgUids); } }

Básicamente, estoy comenzando con una relación de generador de consultas y agregando o en qué condiciones. En el caso de encontrar todas las organizaciones infantiles, utilizo una función recursiva para profundizar en las relaciones.

Una vez que tengo la relación recursiveChildOrganizations, ejecuté la única función recursiva necesaria. Todas las otras relaciones (les he mostrado clientes recursivos pero podría tener muchos) usan esto.

Evito crear una instancia de los objetos en cada turno posible, ya que el generador de consultas es mucho más rápido que crear modelos y trabajar con colecciones.

Esto es mucho más rápido que crear una colección y empujar de forma recursiva a sus miembros (que fue mi primera solución), y como cada método devuelve un generador de consultas y no una colección, se acumula maravillosamente con los ámbitos o cualquier otra condición que desee usar.


Estamos haciendo algo similar, pero nuestra solución fue esta:

class Item extends Model { protected $with = [''children'']; public function children() { $this->hasMany(App/Items::class, ''parent_id'', ''id''); } }


Estoy haciendo algo similar. Creo que la respuesta es almacenar en caché la salida y borrarla cada vez que se actualice la base de datos (siempre que las cuentas no cambien mucho).