private static function generateHasManyJoinTable($ins, $attr, $assocClassName, $dal)
 {
     Logger::getInstance()->pm_log("TableGen::generateHasManyJoinTable");
     $tableName = YuppConventions::relTableName($ins, $attr, new $assocClassName());
     //Logger::struct($this->getDataFromObject( new ObjectReference() ), "ObjRef ===");
     // "owner_id", "ref_id" son FKs.
     // Aqui se generan las columnas, luego se insertan las FKs
     // =========================================================
     $pks = array(array('name' => 'id', 'type' => Datatypes::INT_NUMBER, 'default' => 1));
     $cols = array();
     // FIXME: todo lo declarado aqui esta declarado en la clase ObjectReference,
     //        deberia hacerse referencia a eso en lugar de redeclarar todo
     //        (como los atributos y restricciones).
     $cols[] = array('name' => "owner_id", 'type' => Datatypes::INT_NUMBER, 'nullable' => false);
     $cols[] = array('name' => "ref_id", 'type' => Datatypes::INT_NUMBER, 'nullable' => false);
     $cols[] = array('name' => "type", 'type' => Datatypes::INT_NUMBER, 'nullable' => false);
     $cols[] = array('name' => "deleted", 'type' => Datatypes::BOOLEAN, 'nullable' => false);
     $cols[] = array('name' => "class", 'type' => Datatypes::TEXT, 'nullable' => false);
     // El tema con la columna ord es que igual esta declarada en la clase ObjectReference,
     // entonces las consultas que se basen en los atributos que tenga la clase van a hacer
     // referencia a "ord" aunque la coleccion hasMany no sea una lista.
     // Entonces lo que hago es generar igual la columna ord aunque la coleccion no sea lista,
     // y queda nullable, asi si es SET o COLLECTION no se da bola a ord.
     $cols[] = array('name' => "ord", 'type' => Datatypes::INT_NUMBER, 'nullable' => true);
     // Si es una lista se genera la columna "ord".
     /*
     $hmattrType = $ins->getHasManyType( $attr );
     if ( $hmattrType === PersistentObject::HASMANY_LIST )
     {
        $cols[] = array(
                'name' => "ord",
                'type' => Datatypes :: INT_NUMBER, // Se de que tipo, esta definido asien PO.
                'nullable' => true
               );
     }
     */
     $dal->createTable2($tableName, $pks, $cols, array());
 }
 /**
  * Se usa solo desde PO::aRemoveFrom y PO::aRemoveAllFrom.
  * 
  * ES COMO LO CONTRARIO DE SAVE_ASSOC, pero para solo un registro. save_assoc( PersistentObject &$owner, PersistentObject &$child, $ownerAttr )
  * Elimina la asociacion hasMany entre los objetos. (marca como eliminada o borra fisicamente el registro en la tabla de join correspondiente a la relacion entre los objetos).
  * attr1 es un atributo de obj1
  * attr2 es un atributo de obj2
  * attr1 y attr2 corresponden a los roles de la misma asociacion entre obj1 y obj2
  * attr1 y/o attr2 debe(n) ser hasMany
  * logical indica si la baja es fisica o logica.
  */
 public function remove_assoc($obj1, $obj2, $attr1, $attr2, $logical = false)
 {
     Logger::getInstance()->pm_log("PM::remove_assoc");
     // TODO: Si la relacion es A(1)<->(*)B (bidireccional) deberia setear en NULL el atributo A y A_id de B.
     // Veo cual es el owner:
     $owner =& $obj1;
     $ownerAttr =& $attr1;
     $child =& $obj2;
     if ($obj1->getClass() != $obj2->getClass() && $obj2->isOwnerOf($attr1)) {
         $owner =& $obj2;
         $ownerAttr =& $attr2;
         $child =& $obj1;
     }
     Logger::getInstance()->log('PM::remove_assoc owner ' . $owner->getClass() . ', child ' . $child->getClass());
     // Para eliminar no me interesa el tipo de relacion (si esta instanciada bidireccional o unidireccional).
     // Quiero eliminar el que tenga ownerid y childid de los objetos que me pasaron.
     // (obs: entonces no permito mas de una relacion entre 2 instancias!)                               );
     // El id de la superclase, es igual que el id de la clase declarada en el hasMany, y el mismo que la instancia final
     // Por eso uso el id del objeto directamente
     $ref_id = $child->getId();
     Logger::getInstance()->log('PM::remove_assoc owner_id ' . $owner->getId() . ', ref_id ' . $ref_id);
     // se pasan instancias... para poder pedir el withtable q se setea en tiempo de ejecucion!!!!
     //
     $tableName = YuppConventions::relTableName($owner, $ownerAttr, $child);
     // Necesito el id del registro para poder eliminarlo...
     // esto es porque no tengo un deleteWhere y solo tengo un delete por id... (TODO)
     YuppLoader::load("core.db.criteria2", "Query");
     $q = new Query();
     $q->addFrom($tableName, "ref")->addProjection("ref", "id")->setCondition(Condition::_AND()->add(Condition::EQ("ref", "owner_id", $owner->getId()))->add(Condition::EQ("ref", "ref_id", $ref_id)));
     $data = $this->dal->query($q);
     $id = $data[0]['id'];
     // Se que hay solo un registro...
     // TODO: podria no haber ninguno, OJO! hay que tener en cuenta ese caso.
     $this->dal->deleteFromTable($tableName, $id, $logical);
 }