Duda Codeigniter y ORM DataMapper

S

Hola, tengo ya mi base de datos diseñada y he insertado unos registros sin problemas.

El problema me sale cuando en mis tablas intermedias tengo que insertar información, es decir, hacer las relaciones. ¿estas relaciones he de hacerlas a mano? en caso de insertar nuevos registros que deben de tener relación con otros de otra tabla debo relacionarlo antes de insertarlo??

Las foreign-keys entonces no son necesarias definirlas?

PiPePiTo

#1 No es necesario hacer relaciones en las tablas. No es necesario, pero sí altamente recomendado.

Básicamente las relaciones las tienes ahí para que no puedas borrar por ejemplo un registro al que luego otra tabla va a hacer uso en cualquier momento, aunque sea su ID. También mejoran la velocidad en las consultas...etc...

Luego por ejemplo, no podrás añadir info en un campo que venga de otra tabla si dicha info (véase la id de usuario por ejemplo) no existe en la tabla usuarios...

Ojo, que puedo equivocarme, pero yo siempre lo he entendido así.

Dicho esto... sigo sin entender tu duda x'D

S

Si, la verdad que no lo explico nada claro. Lo pongo con ejemplos:

Tengo dos tablas

departaments
id
nombre
email
.......(mas atributos)

persons
id
nombre
apellidos
email
........(mas atributos)

Para estas dos tablas me hago una tabla de reunión
departaments_persons
id
departament_id
person_id

Esta nueva tabla debe de contener algún tipo de información y es que si por ejemplo tengo una persona 1 que trabaja en un departamento 2, tendría una fila en la nueva tabla con id = 1 departament_id = 2 y person_id = 1. Pues bien, esa información que rellena la nueva tabla tengo que hacerla de forma manual? se hace de forma automática? Antes cuando no usaba datamapper no tenia una tabla intermedia y por tanto me salía automáticamente con que registro de la otra tabla quería relacionarlo, ahora al tener una tabla intermedia no se como debo hacerlo.

1 respuesta
PiPePiTo

#3 Si lo he entendido bien, lo que tienes que hacer es directamente insertar la info que te interesa en la tabla del "medio" es decir, cada vez que a la persona 5 le asignas un departamento lo que estás haciendo es meter en la tabla departaments_persons un id automático (sería lo suyo) e insertar, id de persona e id de departamento.

Para poder hacer eso primero tiene que existir dicho departamento y dicha persona, por supuesto. Al crear la relación lo que evitas también es poder borrar la persona 5 dejando información acerca de en qué departamentos está, ya que si hay información vinculada a dicha persona en cualquier tabla relacionada primero te dirá que te la cepilles toda para poder borrar a la persona. Al igual que pasaría con el departamento.

P.D. ¿estás haciéndolo en inglés?

1 respuesta
MTX_Anubis

Busca relaciones many to many en datamapper pero se hace de forma automática. No recuerdo cómo porque hace año y medio que no lo toco (lo usé para una asignatura) pero poder, se puede.

1 respuesta
S

#4 Siento contestar tan tarde, lo estoy haciendo en inglés porque pensaba que con datamapper los nombres de las tablas debían ir en inglés, por el tema de los plurales y eso. Si eso no es relevante lo cambiaré a español.

Entonces para que la tabla departaments_persons se rellene tengo que hacer yo las inserciones cogiendo los datos que me interesen de las tablas a las que reúne, es decir, el ejemplo que me pones de la persona 5 y el departamento X tendría que hacerlo de forma manual. Y Las foreign-keys que defino, me van a dejar insertar o borrar en esa tabla de reunión (departaments_persons) si los datos que pretendo introducir forman parte de las otras tablas.

S

#5 Las relaciones many to many las uso, pero eso de hacerlo de forma automatica es lo que pregunto como hacer :P

10 días después
S

Pongo todos los datos de los que consta mi aplicación a ver si alguien me puede ayudar.

Voy a realizar una aplicación para el control de consumibles e impresoras. Esta va a tener las siguientes tablas :

http://img854.imageshack.us/img854/6394/20130404114013.jpg

Como se puede observar las tablas dibujadas a mano son tablas de reunión que me he hecho para poder relacionarlas entre sí a las tablas principales.

Tengo los siguientes modelos para cada una de mis tablas principales. Este es el código de cada modelo.

Tabla Deparatamento

class Departament extends DataMapper {

var $has_many = array('person','device');

function __construct($id = NULL)
{
	parent::__construct($id);
}
}

Tabla Dispositivo

class Device extends DataMapper {

var $has_one = array('departament','provider','order');

var $has_many = array(
		'element' => array(
			'class' => 'element',
			'other_field' => 'device',
			'join_self_as' => 'device',
			'join_other_as' => 'element',
			'join_table' => 'devices_elements')
	);

function __construct($id = NULL)
{
	parent::__construct($id);
}

}

Tabla Elemento

class Element extends DataMapper {

var $has_one = array('provider','order');

var $has_many = array(
		'device' => array(
			'class' => 'device',
			'other_field' => 'element',
			'join_self_as' => 'element',
			'join_other_as' => 'device',
			'join_table' => 'devices_elements')
	);

function __construct($id = NULL)
{
	parent::__construct($id);
}

}

Tabla Compra

class Order extends DataMapper {

var $has_many = array('devices','elements');

function __construct($id = NULL)
{
	parent::__construct($id);
}

}

Tabla Persona

class Person extends DataMapper {

var $has_one = array('departament');

function __construct($id = NULL)
{
	parent::__construct($id);
}

}

Tabla Proveedor

class Provider extends DataMapper {

var $has_many = array('device','element');

function __construct($id = NULL)
{
	parent::__construct($id);
}

}

Tengo en cada modelo validaciones pero las he quitado para no expandir esto más.

Bueno mi pregunta es:
¿Esta bien que para unir dos tablas me haga una tabla intermedia? Si es así, ¿Tengo que insertar los datos de esas tablas intermedias manualmente?

Otra pregunta:
¿He de crear foreign-keys?

Gracias y siento poner este tocho :P

PiradoIV

#1 ¡Buenas !

DataMapper trabaja de manera muy sencilla con relaciones, por lo que veo no has tenido ningún problema en crear las tablas en la base de datos, así que puedes pasar directamente a la acción.

Te pongo un ejemplo práctico, avísame si tienes problemas:

<?php

$this->load->model('person');
$this->load->model('order');
$person = new $this->person();
$order = new $this->order();

$person->where('id', $id)->limit(1)->get();

$order = new $this->order();
$order->observaciones = 'Blah blah blah';
// Guardamos la compra
$order->save();
// Relacionamos esa compra con el usuario
$person->save($order);

// También se puede guardar la compra y la relación directamente
$order->save($person);

// O muchas relaciones a la vez
$person->save(array($order, $payment, $loquequieras));

La documentación de DataMapper está muy bien, échale un ojo a la sección Save (busca Save a simple relationship, Save multiple relations, etc)

¡Saludos!

2 2 respuestas
PiPePiTo

#9 Gracias a Dios, llevo días sin poder echarle un vistazo apra echarle una mano y has llegado como caido del cielo :D

1
S

#9 Vale ya comprendo como relacionar varias tablas, me ha sido de gran utilidad :D

Solo una última cosa, he de hacer foreign-keys entre las tablas? o con hacer esas tablas intermedias me puedo olvidar de hacerlas?

2 respuestas
JuShTo

#11

Yo no entiendo nada de datamapper pero lo lógico es que tengas que hacer foreignkeys para restringir los datos que puedes meter a las tablas.

1 respuesta
S

#11 Vale, pensaba que ya teniendo tablas externas no serian necesarias, pero lo que dices tiene sentido.

Otra duda que me surge, si yo quiero insertar un registro (un elemento) y ese elemento debe estar relacionado con un dispositivo, he visto que puedo agregar una regla de validación para las relaciones, concretamente en esta parte de la documentación: http://datamapper.wanwizard.eu/pages/validation.html#Rules

El ejemplo que viene lo comprendo,consiste en un usuario que debe estar relacionado con un grupo, por lo tanto en las validaciones para el usuario agrego una regla de grupo. Si yo quiero guardar un usuario tendré que guardar a su vez una relación de Grupo.
Si yo quiero establecer una regla de validación para que haya una relación con dispositivo ¿ debería de agregar el siguiente código?

'device' => array(
        'label' => 'Device',
        'rules' => array('required')
    )
PiradoIV

#11 #12 En el único caso que necesitas usar obligatoriamente foreign keys es si no quieres crear una tabla intermedia de uniones, en la documentación te ponen este ejemplo:

countries: id, code, name
users: id, password, email, country_id

Esta feature depende de la versión de DataMapper, al principio las tablas intermedias eran obligatorias siempre, incluso para los one-to-one / one-to-many.

Sobre lo que comentas acerca de la validación, tal y como lo has puesto está bien, tienes que tener en cuenta que únicamente vas a poder guardar un usuario con esa validación si directamente lo guardas con el grupo:

// No funcionaría
$usuario->save();
$grupo->save($usuario);

// Sí funcionaría
$usuario->save($grupo);

De otra manera dará un error de validación

1 respuesta
S

#14 Entonces si no quiero crear tablas intermedias para tablas que tienen relación one-to-one o one-to-many no es necesario??? lo digo porque veo mucho mas limpio el proyecto sin tantas tablas externas. Obviamente estoy usando la última versión de dataMapper.

1 respuesta
PiradoIV

#15 No lo he probado, pero no deberías tener problemas, ¡pruébalo y nos cuentas! :)

1 respuesta
S

#16 De acuerdo, voy a probarlo y cuando lo tenga comento :)

S

Aparentemente parece que se pueden hacer relaciones one-to-one y one-to-many sin necesidad de tablas intermedias. La cosa es que veo absurdo pues realizar manualmente la relación.

He probado a relacionar dos tablas: persons y departaments

tabla persons
------------------

id
nombre
ap1
....
departament_id

tabla departaments
-------------------------

id
nombre
........

La relación es que una persona tiene que pertenecer a uno y solo un departamento y este departamento puede tener muchas personas asociadas a él, por lo tanto una relación one-to-many. Para ello he agregado un atributo en la tabla persons (departament_id) que va a ser un índice y este se va a relacionar con la id de mi tabla departament a través de una foreign-key. Así tengo mi relación establecida y por medio de un formulario que es lo más normal, le digo con que departamento estará esa persona relacionada y por lo tanto no hay necesidad de hacer esa sentencia de relación, $person->save($departament)

Si alguien ve que no es lo correcto que me lo comente, un saludo!

Usuarios habituales