Al realizar una consulta que debía regresarme un sólo resultado, me regresaba 2 e incluso 4. Esto se debía a que existen registros ‘duplicados’ -la tabla no tiene una llave primaria, huh? no pregunten-

Bueno, entonces me interesaba obtener sólo el registro más actual, por suerte, la tabla si tiene un campo con la fecha que se creó el registro.

Para limitar el número de resultados varía de acuerdo a la base de deatos que estes utilizando, por ejemplo, en MySQL es con la palabra LIMIT, en SQL Server con TOP y en Oracle con ROWNUM

Así que, en Oracle, la consulta más simple que se me ocurrió fue la siguiente

SELECT *
FROM USERS
WHERE ID = :ID
AND ROWNUM <= 1
ORDER BY FECHA_ALTA DESC

Pero no me arrojó los resultados esperados, de hecho, siempre me regresaba el mismo registro aunque creará un registro más actual. Esto se debe al orden en que Oracle ejecuta los comandos de la sentencia -primero ejecuta la claúsula WHERE que regresa un sólo registro y luego lo ordena de acuerdo a ORDER BY (si, ordena un sólo registro)-

La solución es realizar una subconsulta de la siguiente manera

SELECT * FROM (
SELECT *
FROM USERS
WHERE ID = :ID
ORDER BY FECHA_ALTA DESC
) WHERE ROWNUM <= 1

Fuentes:
http://www.w3schools.com/sql/sql_top.asp
http://www.oracle.com/technetwork/issue-archive/2006/06-sep/o56asktom-086197.html

A diferencia de AngularJS, ionic utiliza el módulo ui-router en vez de ngRoute para el mecanismo de enrutamiento de las páginas.
En nuestra configuración tendremos estados en vez de rutas. Por ejemplo,

phonecatApp.config(['$routeProvider',
  function($routeProvider) {
    $routeProvider.
      when('/phones', {
        templateUrl: 'partials/phone-list.html',
        controller: 'PhoneListCtrl'
      }).
      when('/phones/:phoneId', {
        templateUrl: 'partials/phone-detail.html',
        controller: 'PhoneDetailCtrl'
      }).
      otherwise({
        redirectTo: '/phones'
      });
  }]);

se convertiría en

    phonecatApp.config(function ($stateProvider, $urlRouterProvider) {
        $stateProvider

            .state('phones', {
                url: '/phones',
                templateUrl: 'partials/phone-list.html',
                controller: 'PhoneListCtrl'
            })

            .state('phones.detail', {
                url: '/:phoneId',
                templateUrl: 'partials/phone-detail.html',
                controller: 'PhoneDetailCtrl'
            })

        $urlRouterProvider.otherwise('/phones')
    })

Y para navegar a otra página, supongamos que tenemos un botón en nuestra plantilla

<button class="button button-block button-positive" ng-click="goTo(phoneId)">
                Detail
</button>

nuestro controlador quedaría

    .controller('PhoneListCtrl', ['$scope', '$state', function($scope, $state){
        $scope.goTo = function(phoneId){
            $state.go('phones.detail', {phoneId: phoneId})
        }
    }])

notesé el paso del parámetro ‘phoneId’

Fuentes:

Desarrollé un servicio web que regresa una respuesta al estilo de SmartGWT

{
"response": {
"status": 0,
"startRow": 0,
"endRow": 76,
"totalRows": 546,
"data": [
{"field1": "value", "field2": "value"},
{"field1": "value", "field2": "value"},
… 76 total records …
]
}
}

Queremos utilizar estos datos en nuestra plantilla

distritos.html

...
<label class="item item-input item-select">
                <div class="input-label">
                    Distrito
                </div>
                <select>
                    <option ng-repeat="distrito in distritos">
                        {{ distrito.descripcion }}
                    </option>
                </select>
            </label>
...

Hay dos formas para poder consumir esta respuesta en nuestra plantilla -a través de un servicio de AngularJS-

Una es utilizar una función transformResponse en la configuración del servicio de la siguiente manera

services.js

'use strict'
angular.module('Equinox.services', ['ngResource'])

    .factory('Distritos', ['$resource', function ($resource) {
        return $resource('http://localhost:8080/equinox/catalogos/distritos', {}, {
            'query': {method: 'GET', isArray: true, transformResponse: function(data){
                return angular.fromJson(data).response.data
            }}
        })
    }])

controllers.js

angular.module('Equinox.controllers', [])

    .controller('DistritosCtrl', ['$scope', 'Distritos', function ($scope, Distritos) {
        $scope.distritos = Distritos.query()

    }])

y la segunda forma es utilizar la respuesta tal y como viene del servidor

services.js

'use strict'
angular.module('Equinox.services', ['ngResource'])

    .factory('Distritos', ['$resource', function ($resource) {
        return $resource('http://localhost:8080/equinox/catalogos/distritos', {}, {
            'query': {method: 'GET', isArray: false}
        })
    }])

controllers.js

angular.module('Equinox.controllers', [])

    .controller('DistritosCtrl', ['$scope', 'Distritos', function ($scope, Distritos) {
        Distritos.query().$promise.then(function(data){
            $scope.distritos = data.response.data
        })
    }])

Fuentes:

En Oracle, si necesitas utilizar el año actual (de la base de datos) para el valor de alguna columna de tipo Number, lo podríamos hacer de la siguiente manera

    INSERT INTO TEXP
            (FOLIO,
             NUMERO,
             ANYO
            )
         VALUES (SEQ_TEXP.NEXTVAL,
             (SELECT MAX (NUMERO) + 1
                FROM TEXP
               WHERE ANYO = TO_NUMBER(TO_CHAR (SYSDATE, 'YYYY'))
             ),
             TO_NUMBER(TO_CHAR (SYSDATE, 'YYYY'))
            );

En este caso la tabla TEXP tiene 3 columnas de tipo Number (FOLIO, NUMERO Y ANYO).
Para obtener el FOLIO utilizamos una secuencia, para obtener el NUMERO hacemos una subconsulta para saber cúal es el valor máximo para el año actual y sumamos 1, para el ANYO utilizamos el año actual.
Pues resulta que no es necesario utilizar la función TO_NUMBER, la base de datos hace la conversión automática de un valor de tipo CHAR (o VARCHAR) a NUMBER y visceversa. De hecho la conversión que hace la base de datos es más eficiente que utilizar la función TO_NUMBER (el doble, 20ms contra 10ms para esta consulta sencilla).

    INSERT INTO TEXP
            (FOLIO,
             NUMERO,
             ANYO
            )
         VALUES (SEQ_TEXP.NEXTVAL,
             (SELECT MAX (NUMERO) + 1
                FROM TEXP
               WHERE ANYO = TO_CHAR (SYSDATE, 'YYYY')
             ),
             TO_CHAR (SYSDATE, 'YYYY')
            );

Fuentes:
http://stackoverflow.com/questions/1119710/how-do-i-get-the-current-year-using-sql-on-oracle

En datanucleus existe un mecanismo llamado attach/detach que sirve para acceder a las propiedades de los objetos fuera del contexto de una transacción. Esto es muy útil, por ejemplo, cuando estructuras tu aplicación en librerías o capas.

Supongamos que tenemos la siguiente clase

    @PersistenceCapable
    public class Audiencia {</p><pre><code>    @PrimaryKey
    @Persistent
    Integer id;
    @Persistent
    Juez juez;
    @Persistent
    Date inicio;
    @Persistent
    Date fin;
    @Persistent
    TipoAudiencia tipo;

    public Audiencia(){
    }

    public static List&lt;Audiencia&gt; getAudiencias(Integer idJuez) {
        List&lt;Audiencia&gt; audiencias;
        PersistenceManager pm = PMF.get().getPersistenceManager();
        Transaction tx = pm.currentTransaction();
        try{
            tx.begin();
            String filter = "juez.id == :idJuez";
            Query query = pm.newQuery(Audiencia.class, filter);
            audiencias = (List&lt;Audiencia&gt;) pm.detachCopyAll((List&lt;Audiencia&gt;)query.executeWithArray(idJuez));
            tx.commit();
        }finally{
            if(tx.isActive()){
                tx.rollback();
            }
            pm.close();
        }
        return audiencias;
    }

}
</code></pre><p>

cabe destacar que dentro del contexto de la transacción podríamos leer las propiedades Juez y TipoAudiencia, datanucleus cargaría los objetos relacionados de forma “lazy loading”. Pero si trataramos de leer alguna propiedad fuera de este contexto -es el caso cuando ejecutamos el método getAudiencias desde otra clase- está tendría el valor null. Datanucleus sólo hace el detach de las propiedades en el Default Fetch Group. Para poder utilizar las demás propiedades, podemos especificar un Fetch Group dinámico de la siguiente manera

    public static List getAudiencias(Integer idJuez, String[] fields) {
        List audiencias;
        PersistenceManager pm = PMF.get().getPersistenceManager();
        Transaction tx = pm.currentTransaction();
        try{
            tx.begin();
            FetchGroup fetchGroup = PMF.get().getFetchGroup(Audiencia.class, "fields");
            fetchGroup.addMembers(fields);
            pm.getFetchPlan().addGroup("fields");
            String filter = "juez.id == :idJuez";
            Query query = pm.newQuery(Audiencia.class, filter);
            audiencias = (List) pm.detachCopyAll((List)query.executeWithArray(idJuez));
            tx.commit();
        }finally{
            if(tx.isActive()){
                tx.rollback();
            }
            pm.close();
        }
        return audiencias;
    }

Fuentes:
http://www.datanucleus.org/products/accessplatform/jdo/fetchgroup.html
http://www.datanucleus.org/products/datanucleus/jdo/attachdetach.html
http://www.datanucleus.org/products/datanucleus/jdo/object
lifecycle.html

Para modificar la consulta de un DataSet puedes utilizar la sección “Property Binding”

en mi caso necesitaba reemplazar en la conulta el valor de un parámetro.

Para reemplazar una cadena con otra lo puedes hacer en el “Expression Builder” de la siguiente manera



var q=new Packages.java.lang.String("SELECT COUNT(*) AS TOTAL \
FROM @OFICINA.EMPLEADOS A, @OFICINA.PUESTOS R, \
@OFICINA.SALARIOS D, @OFICINA.DEPTOS O \
WHERE A.NID_ACO_EXP= R.NID_ACO \
R.NID_DMD=D.NID_DMD AND R.NORDEN=O.NID_ORDEN \
AND TRUNC(R.FECHA) BETWEEN :INICIO AND :FIN");
q.replaceAll("@OFICINA",params["OFICINA"].value);

el código es javascript, pero podemos utilizar clases Java también. En este caso utilizamos la clase String de Java en vez de Javascript, porque el método de javascript no reemplaza todas las coincidencias.

Fuentes:
birt exchange

Recientemente empecé a utilizar Datanucleus para simplificar la persistencia y consulta de datos. Uno de los primeros problemas que tuve fue que al realizar una consulta por segunda vez, las propiedades del objeto eran nulas. Esto se debe al ciclo de vida de los objetos en Datanucleus, el cuál aparece en el log de la siguiente manera

13:07:41,197 DEBUG [DataNucleus.Lifecycle] – Object “mx.com.apestudio.videohaus.server.model.Video@6eb5ec12” (id=”mx.com.apestudio.videohaus.server.model.Video:bb56da010129448ab28f4486d32036b9    “) has a lifecycle change : “P_CLEAN”->”HOLLOW”

al cambiar del estado P_CLEAN a HOLLOW todas las propiedades, excepto la llave primaria, son reestablecidas a un valor nulo. Para evitar que esto suceda, podemos establecer la propiedad RetainValues a true en el archivo de configuración datanucleus.properties

datanucleus.RetainValues=true

al hacer esto, el log muestra lo siguiente

14:05:37,400 DEBUG [DataNucleus.Lifecycle] – Object “mx.com.apestudio.videohaus.server.model.Video@795cd696” (id=”mx.com.apestudio.videohaus.server.model.Video:bb56da010129448ab28f4486d32036b9    “) has a lifecycle change : “P_CLEAN”->”P_NONTRANS”

ahora el objeto pasó de un estado P_CLEAN a P_NONTRANS y conservó todas las propiedades con los valores obtenidos al realizar la primer consulta. Este modo es conveniente si sólo vas a realizar operaciones de lectura.

La otra opción es establecer la propiedad DetachAllOnCommit que, aunque es un poco mas costosa en cuanto a rendimiento, hace un ‘detach’ y ‘re-attach’ automático de los objetos. Esto es especialmente útil si vamos a actualizar alguna propiedad del objeto y queremos persistir los cambios.

datanucleus.DetachAllOnCommit=true

estas propiedades también podemos establecerlas mediante los métodos correspondientes del objeto PersistenceManager.

Cabe destacar que el problema de los valores nulos se presenta sólo cuando queremos leer propiedades del objeto fuera del contexto de una transacción.

Fuentes:
http://stackoverflow.com/questions/4630142/datanucleus-jdo-setting-fields-to-null
http://www.datanucleus.org/products/datanucleus/jdo/object_lifecycle.html
http://www.datanucleus.org/products/datanucleus/persistence_properties.html#RetainValues  
http://www.datanucleus.org/products/accessplatform_3_1/jdo/performance_tuning.html#Reading_persistent_objects_outside_a_transaction_and_PersistenceManager