No se puede hacer que Eloquent cree Uniones Automáticamente


Disculpas por adelantado si la respuesta a mi pregunta es obvia. He hecho mi debida diligencia en la investigación de este tema antes de publicar aquí.

La mayor parte de mi experiencia en framework proviene del uso de CodeIgniter, por lo que nunca he tenido experiencia práctica con OR. (CI tiene algunas soluciones off listas para usar, pero nunca las he usado.)

Me gustaría usar la funcionalidad built incorporada en el Eloquent Lar de Laravel para unirme automáticamente a las mesas de torneos y países juntos al ejecutar una consulta , y devolver el conjunto de datos a que incluye datos de torneos, así como sus datos de países asociados.

Es decir, quiero que Eloquent reconozca la relación de clave externa automáticamente para que pueda ejecutar una consulta (por ejemplo, Tournament::with('Country')->all()) que devolverá todo el conjunto de datos del torneo y del país.

Por favor, detenme ahora mismo si estoy usando Eloquent de una manera que nunca fue la intención de ser utilizado! Mi confusión puede ser más sobre mí tratando de mezclar una solución insostenible en lugar de un error de sintaxis o codificación.

Pregunta que Me Gustaría Replicar en Eloquent

SELECT * FROM tournaments LEFT JOIN countries ON tournaments.country_id = countries.id

Resultado esperado en PHP

Espero recibir una matriz de objetos de Torneo (en PHP), donde se vería un solo objeto de Torneo como:

  • tournaments.id
  • torneos.año
  • torneos.country_id
  • torneos.created_at
  • torneos.updated_at
  • countries.id
  • países.código
  • countries.name
  • países.url
  • países.created_at
  • países.updated_at

Intentos Fallidos Que He Hecho Hasta Ahora

Ejecuté todos estos intentos en un método de controlador ficticio y mostré el resultado como un cadena formateada al generador de perfiles.

Intento fallido # 1: {[56]]}

Código PHP en el controlador ficticio:

$tournaments = Tournament::with('Country')->all();

Genera la siguiente consulta:

SELECT * FROM `tournaments`

El intento #1 devuelve:

Una matriz que contiene objetos de torneo que solo incluyen las columnas de la mesa de torneos.

Intento fallido # 2

Código PHP en el controlador ficticio:

$tournaments = Tournament::with('Country')->first();

Genera el siguiente error:

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'tournament_id' in 'where clause'

SQL: SELECT * FROM `countries` WHERE `tournament_id` IN (?)

Bindings: array (
0 => '1',
)

Otros intentos fallidos

He probó varias combinaciones de convenciones de nomenclatura (por ejemplo, columnas, tablas, etc.).) en vano. También he intentado crear la consulta en Fluent, que funcionó bien, pero me requirió especificar las uniones que es lo que estoy tratando de evitar.

Mi Entorno

  • PHP: 5.3.13
  • MySQL: 5.1.53
  • Laravel: 3.2.3{[29]]}

Relación Entre Los Cuadros

  • relación uno-a-uno
  • Un torneo debe tener un país (hay un extranjero key constraint to enforce it)
  • Un país puede pertenecer a muchas otras relaciones (por ejemplo, un participante, que no se muestra aquí, tiene un país de nacimiento)

Cuadro de países

CREATE TABLE `countries` (                                                                                                                                                                                                                 
`id` int(11) NOT NULL AUTO_INCREMENT,                                                                                                                                                                                                       
`code` varchar(4) NOT NULL,                                                                                                                                                                                                                 
`name` varchar(25) NOT NULL,                                                                                                                                                                                                                
`url` varchar(25) NOT NULL,                                                                                                                                                                                                                 
`created_at` datetime NOT NULL,                                                                                                                                                                                                             
`updated_at` datetime NOT NULL,                                                                                                                                                                                                            
PRIMARY KEY (`id`),                                                                                                                                                                                                                        
UNIQUE KEY `countries_code_unique` (`code`),                                                                                                                                                                                               
KEY `countries_url_index` (`url`)                                                                                                                                                                                                          
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=latin1

Tabla de torneos

CREATE TABLE `tournaments` (                                                                                                                                                                                                             
`id` int(11) NOT NULL AUTO_INCREMENT,                                                                                                                                                                                                       
`year` int(11) NOT NULL,                                                                                                                                                                                                                    
`country_id` int(11) NOT NULL,                                                                                                                                                                                                              
`created_at` datetime NOT NULL,                                                                                                                                                                                                             
`updated_at` datetime NOT NULL,                                                                                                                                                                                                             
PRIMARY KEY (`id`),                                                                                                                                                                                                                         
UNIQUE KEY `tournaments_year_unique` (`year`),                                                                                                                                                                                             
KEY `tournaments_country_id_foreign` (`country_id`),                                                                                                                                                                                      
CONSTRAINT `tournaments_country_id_foreign` FOREIGN KEY (`country_id`) REFERENCES `countries` (`id`) ON UPDATE CASCADE                                                                                                                  
) ENGINE=InnoDB AUTO_INCREMENT=40 DEFAULT CHARSET=latin1

Modelo de países (países.php)

class Country extends Eloquent {
    public static $timestamps = true;
    public static $table = 'countries';
}

Modelo de torneos (torneos.php)

class Tournament extends Eloquent {
    public static $timestamps = true;

    public function country()
    {
        return $this->has_one('Country');
    }
}
Author: Laurence, 2012-06-19

4 answers

Claramente with('Country') o with('country') no hace ninguna diferencia debido al hecho de que logró obtener el siguiente error:

Column not found: 1054 Unknown column 'tournament_id' in 'where clause'

SQL: SELECT * FROM `countries` WHERE `tournament_id` IN (?)

Lo malo es cómo se define la relación: Un torneo debe tener un país sería un torneo necesita pertenecer a un país, y no tiene un país. Así que para resolver este cambio la relación a

public function country()
{
    return $this->belongs_to('Country');
}
 9
Author: crynobone,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-20 15:59:53

Según los documentos Elocuentes:

Nota: Todos los métodos disponibles en el generador de consultas también están disponibles al consultar modelos Eloquent.

Así que con eso en mente algo como:

DB::table("tournament")->join("countries","tournaments.country_id","=","countries.id")->get();

Debe ser replicable en Eloquent. Yo personalmente uso la versión query builder ahora mismo que puede que desee utilizar, pero voy a tratar de probar con Eloquent cuando tenga la oportunidad y actualizar esto.

ACTUALIZACIÓN:

Sí, usando el generador de consultas de Eloquent métodos que puede tener:

Tournament::join("countries","tournaments.country_id","=","countries.id")->get();

Esto devolverá un modelo de torneo que incluye los campos de ambas mesas.

HTH

 2
Author: sturrockad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-13 12:39:25

Tu cláusula 'con' pide 'País', pero tu código lo declara como 'país'.

Entonces, debería:

$tournaments = Tournament::with('Country')->all();

Be:

$tournaments = Tournament::with('country')->all();

Porque en tu Modelo de Torneos, has definido esto como:

public function country()
{
    return $this->has_one('Country');
}

¿Hacer este cambio lo resuelve?

 1
Author: James Healey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-19 11:48:56

Debes asegurarte de que tu relación esté declarada en tu modelo de Torneo:

public function country() {
    return $this->has_one('Country');
}

Además, tendrá que declarar lo contrario en su modelo de País:

public function tournament() {
    return $this->belongs_to('Tournament');
}

En este punto, puede acceder al objeto torneo asociado con el objeto país de la siguiente manera:

$tournaments = Tournament::with('country')->all();
foreach ($tournaments as $tournament) {
    echo $tournament->country;
}

Avísame si esto muestra cada país correspondiente al torneo.

 0
Author: Karl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-01 08:47:13