2010-03-30 17 views
84

Tengo dos tablas: pistas y puntos de referencia, una pista puede tener muchos puntos de referencia, pero un punto de ruta se asigna a solo 1 pista.Restricciones de claves foráneas en Android con SQLite? en Eliminar cascada

En la tabla de puntos de camino, tengo una columna llamada "trackidfk" que inserta el track_ID una vez que se realiza una pista; sin embargo, no configuré restricciones de clave foránea en esta columna.

Cuando elimino una pista, quiero eliminar los puntos de referencia asignados, ¿es esto posible ?. Leí sobre el uso de Triggers, pero no creo que sean compatibles con Android.

para crear la tabla de waypoints:

public void onCreate(SQLiteDatabase db) { 
    db.execSQL("CREATE TABLE " + TABLE_NAME 
       + " (" 
       + _ID   + " INTEGER PRIMARY KEY AUTOINCREMENT, " 
       + LONGITUDE + " INTEGER," 
       + LATITUDE + " INTEGER," 
       + TIME  + " INTEGER," 
       + TRACK_ID_FK + " INTEGER" 
       + ");" 
      ); 

    ... 
} 

Respuesta

229

Las restricciones de clave foránea con la cascada de eliminación son compatibles, pero debe habilitarlas.
Acabo de agregar lo siguiente a mi SQLOpenHelper, que parece hacer el truco.

@Override 
public void onOpen(SQLiteDatabase db) { 
    super.onOpen(db); 
    if (!db.isReadOnly()) { 
     // Enable foreign key constraints 
     db.execSQL("PRAGMA foreign_keys=ON;"); 
    } 
} 

He declarado mi columna de referencia de la siguiente manera.

mailbox_id INTEGER REFERENCES mailboxes ON DELETE CASCADE 
+32

Como comentario: esto solo funciona desde la versión sqlite 3.6.19. – VansFannel

+58

Lo que significa que solo funciona desde Android 2.2 Froyo que tiene SQLite 3.6.22 – Intrications

+2

@Phil, ¿por qué utilizas una condición if-read-only? –

4

No creo SQLite apoya esta fuera de la caja. Lo que estoy haciendo en mis aplicaciones es:

  1. Crear transacción
  2. datos Borrar detalle (waypoints en tu ejemplo)
  3. datos maestros eliminar (las pistas en tu ejemplo)
  4. transacción de confirmación en caso de éxito

De esta forma estoy seguro de que se borraron todos los datos o ninguno.

+0

¿Pero está borrando de ambas tablas con un método? – jcrowson

+0

Sí, fui bastante junto con la muestra de Notes de la API. Cuando deba eliminar lo que sería una pista en su caso, creo la transacción, elimino la ruta y los puntos de referencia y confirmo la transacción. Eso es todo de una vez. –

4

Los disparadores son compatibles con Android y ese tipo de eliminación en cascada no es compatible con sqlite. Se puede encontrar un ejemplo del uso de desencadenadores en Android here. Aunque usar transacciones como declaró Thorsten probablemente sea tan fácil como un disparador.

3

versión de SQLite en Android 1.6 es 3.5.9 por lo que no soporta claves foráneas ...

http://www.sqlite.org/foreignkeys.html "En este documento se describe el soporte para claves foráneas introducidas en SQL SQLite versión 3.6. 19. "

En Froyo es SQLite versión 3.6.22, así que ...

EDIT: para ver la versión sqlite: sqlite3 adb shell -versión

+0

Entonces, ¿hay alguna manera de forzar esas restricciones? Quiero decir, ¿hay alguna manera de actualizar la versión de sqlite? Porque debemos tener que admitir la versión de software para Android 2.1 que tiene la versión de sqlite 3.5.9 como la anterior – NullPointerException

+0

No, usted tiene para manejar todo por sí mismo :( – GBouerat

1

Las claves externas con "en la supresión en cascada" son compatibles con SQLite en Android 2.2 y versiones posteriores. Pero tenga cuidado al usarlos: algunas veces se informa un error al activar una clave externa en una columna, pero el problema real reside en otra restricción de clave externa de otra columna en la tabla secundaria o en alguna otra tabla que haga referencia a esta tabla.

Parece que SQLite verifica todas las restricciones al encender una de ellas. En realidad se menciona en la documentación. Controles de restricción DDL frente a DML.

51

Desde Android 4.1 (API 16) SQLiteDatabase apoya:

public void setForeignKeyConstraintsEnabled (boolean enable) 
25

como el puesto de e.shishkin dice API de 16 hasta usted debe habilitar las restricciones de clave externa en el método mediante el SqLiteOpenHelper.onConfigure(SqLiteDatabase)db.setForeignKeyConstraintsEnabled(boolean)

@Override 
public void onConfigure(SQLiteDatabase db){ 
    db.setForeignKeyConstraintsEnabled(true); 
} 
6

Cualquiera que sea @phil mencionado es bueno. Pero puede usar otro método predeterminado disponible en la base de datos para establecer la clave externa. Eso es setForeignKeyConstraintsEnabled (true).

@Override 
public void onOpen(SQLiteDatabase db) { 
    super.onOpen(db); 
    if (!db.isReadOnly()) { 
     // Enable foreign key constraints 
     db.execSQL("PRAGMA foreign_keys=ON;"); 
       //(OR) 
     db.setForeignKeyConstraintsEnabled (true) 
    } 
} 

Para Docs se refieren SQLiteDatabase.setForeignKeyConstraintsEnabled

+2

la documentación que envió sugiere: 'Un buen momento para llamar a este método es correcto después de llamar openOrCreateDatabase (archivo, SQLiteDatabase.CursorFactory) o en el onConfigure (SQLiteDatabase) callback.' Así que en vez de 'onOpen',' onConfigure' parece ser el lugar correcto. –

8

Nunca demasiado viejo de una pregunta a responder con una respuesta más completa.

@Override public void onOpen(SQLiteDatabase db) { 
    super.onOpen(db); 
    if (!db.isReadOnly()) { 
     setForeignKeyConstraintsEnabled(db); 
    } 
    mOpenHelperCallbacks.onOpen(mContext, db); 
} 

private void setForeignKeyConstraintsEnabled(SQLiteDatabase db) { 
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { 
     setForeignKeyConstraintsEnabledPreJellyBean(db); 
    } else { 
     setForeignKeyConstraintsEnabledPostJellyBean(db); 
    } 
} 

private void setForeignKeyConstraintsEnabledPreJellyBean(SQLiteDatabase db) { 
    db.execSQL("PRAGMA foreign_keys=ON;"); 
} 

@TargetApi(Build.VERSION_CODES.JELLY_BEAN) 
private void setForeignKeyConstraintsEnabledPostJellyBean(SQLiteDatabase db) { 
    db.setForeignKeyConstraintsEnabled(true); 
} 
Cuestiones relacionadas