2012-08-16 11 views
7

Estoy buscando una forma de hacer una consulta que requiera un JOIN. ¿Hay alguna manera de hacer esto en una declaración preparada, o es el rawQuery la única opción que tengo? Si rawQuery es la única opción, entonces hay alguna forma de mapear automáticamente los objetos devueltos a los objetos del Dao que se está implementando.ORMLite JOINs, o mapeo automático rawQuery

He buscado los documentos y ejemplos pero no encuentro nada que me permita asignar el resultado de la base de datos sin procesar a una clase de objeto ORM.

+1

FYI Daniel. Acaba de lanzar ORMLite 4.22, que admite consultas JOIN simples. – Gray

+0

Anteriormente tenía ORMLite 4.23 que no admitía las consultas JOIN. Al revisar las fechas de publicación y la marca de tiempo de su comentario, creo que quiso decir que ORMLite 4.26, publicado el 26/09/12, fue la primera versión compatible con consultas simples de JOIN. Acabo de actualizar a 4.45, que definitivamente tiene JOIN. –

Respuesta

15

ORMLite admite simple JOIN queries. También puede usar raw-queries para lograr esto.

Puede usar el Dao.getRawRowMapper() para asignar las consultas tal como las encontró o puede crear un asignador personalizado. La documentación tiene el siguiente código de ejemplo que muestra cómo asignar la String[] en su objeto:

GenericRawResults<Foo> rawResults = 
    orderDao.queryRaw(
    "select account_id,sum(amount) from orders group by account_id", 
    new RawRowMapper<Foo>() { 
      public Foo mapRow(String[] columnNames, 
       String[] resultColumns) { 
       return new Foo(Long.parseLong(resultColumns[0]), 
        Integer.parseInt(resultColumns[1])); 
     } 
    }); 
+0

Gracias @Gray. Encontré todo el material del asignador de filas personalizado, pero solo quería que se asignara automáticamente a un objeto que ya había definido. ¡Una opción de JOIN de QueryBuilder sería la siguiente en mi lista de deseos! ¿Alguna palabra sobre cuándo/si eso viene? – DanO

+0

¿Quieres iniciar un hilo en ormlite-dev? Estoy listo para escribirlo. Lo que será más difícil es usar join para hidratar subobjetos. Pero comienza el hilo y te responderé: https://groups.google.com/forum/?fromgroups#!forum/ormlite-dev – Gray

+1

Creado el hilo. – DanO

8

He encontrado una manera de asignar automáticamente un conjunto de resultados a un objeto modelo.

// return the orders with the sum of their amounts per account 
GenericRawResults<Order> rawResults = 
    orderDao.queryRaw(query, orderDao.getRawRowMapper(), param1) 

// page through the results 
for (Order order : rawResults) { 
    System.out.println("Account-id " + order.accountId + " has " 
    + order.totalOrders + " total orders"); 
} 

rawResults.close(); 

La clave es tirar de la fila asignador de su objeto Dao usando getRawRowMapper(), que se encargará de la asignación para usted. Espero que esto ayude a cualquiera que lo encuentre.

Todavía me encantaría la posibilidad de hacer combinaciones en el QueryBuilder, pero hasta que esto sea compatible, esta es la segunda mejor opción en mi opinión.

0

mapeo automático consulta Raw

tuve problema de la asignación de campos de encargo SELECT que devuelven columnas que no son presente en cualquier modelo de mesa. Así que hice personalizado RawRowMapper que puede mapear campos de consulta personalizada a modelo personalizado. Esto es útil cuando tiene una consulta que tiene campos que no corresponden a ningún modelo de mapeo de tablas.

Ésta es RowMapper que realiza el mapeo consulta automática:

public class GenericRowMapper<T> implements RawRowMapper<T> { 

private Class<T> entityClass; 
private Set<Field> fields = new HashSet<>(); 
private Map<String, Field> colNameFieldMap = new HashMap<>(); 

public GenericRowMapper(Class<T> entityClass) { 
    this.dbType = dbType; 
    this.entityClass = entityClass; 
    Class cl = entityClass; 
    do { 
     for (Field field : cl.getDeclaredFields()) { 
      if (field.isAnnotationPresent(DatabaseField.class)) { 
       DatabaseField an = field.getAnnotation(DatabaseField.class); 
       fields.add(field); 
       colNameFieldMap.put(an.columnName(), field); 
      } 
     } 
     cl = cl.getSuperclass(); 
    } while (cl != Object.class); 
} 

@Override 
public T mapRow(String[] columnNames, String[] resultColumns) throws SQLException { 
    try { 
     T entity = entityClass.newInstance(); 
     for (int i = 0; i < columnNames.length; i++) { 
      Field f = colNameFieldMap.get(columnNames[i]); 
      boolean accessible = f.isAccessible(); 
      f.setAccessible(true); 
      f.set(entity, stringToJavaObject(f.getType(), resultColumns[i])); 
      f.setAccessible(accessible); 
     } 
     return entity; 
    } catch (InstantiationException e) { 
     throw new RuntimeException(e); 
    } catch (IllegalAccessException e) { 
     throw new RuntimeException(e); 
    } 
} 

public Object stringToJavaObject(Class cl, String result) { 
    if (result == null){ 
     return null; 
    }else if (cl == Integer.class || int.class == cl) { 
     return Integer.parseInt(result); 
    } else if (cl == Float.class || float.class == cl) { 
     return Float.parseFloat(result); 
    } else if (cl == Double.class || double.class == cl) { 
     return Double.parseDouble(result); 
    } else if (cl == Boolean.class || cl == boolean.class) { 
     try{ 
      return Integer.valueOf(result) > 0; 
     }catch (NumberFormatException e){ 
      return Boolean.parseBoolean(result); 
     } 
    } else if (cl == Date.class) { 
     DateLongType lType = DateLongType.getSingleton(); 
     DateStringType sType = DateStringType.getSingleton(); 
     try { 
      return lType.resultStringToJava(null, result, -1); 
     } catch (NumberFormatException e) { 
      try { 
       return sType.resultStringToJava(null, result, -1); 
      } catch (SQLException e2) { 
       throw new RuntimeException(e); 
      } 
     } 
    } else { 
     return result; 
    } 
} 
} 

Y aquí está el uso :

class Model{ 
    @DatabaseField(columnName = "account_id") 
    String accId; 
    @DatabaseField(columnName = "amount") 
    int amount; 
} 

String sql = "select account_id,sum(amount) amount from orders group by account_id" 
return queryRaw(sql,new GenericRowMapper<>(Model.class)).getResults() 

Esto devolverá List<Model> con filas de resultados asignados al modelo si columna de la consulta nombres y @DatabaseField(columnName son los mismos