2010-03-11 19 views
5

Considera una aplicación de iPhone que es un catálogo de animales. La aplicación debe permitir al usuario agregar información personalizada para cada animal, digamos una calificación (en una escala de 1 a 5), ​​así como algunas notas que pueden ingresar sobre el animal. Sin embargo, el usuario no podrá modificar los datos del animal en sí. Supongamos que cuando la aplicación se actualiza, debería ser fácil cambiar la parte del catálogo (estática), pero nos gustaría que la parte de información del usuario personalizada (dinámica) se retenga entre las actualizaciones, para que el usuario no pierda ninguna de su información personalizada.iPhone y Core Data: ¿cómo retener los datos ingresados ​​por el usuario entre actualizaciones?

Probablemente querríamos utilizar Core Data para compilar esta aplicación. Digamos también que ya contamos con un proceso previo para leer en los datos de los animales para rellenar previamente el almacén de respaldo (SQLite) que utiliza Core Data. Podemos incrustar este archivo de base de datos en el paquete de la aplicación en sí, ya que no se modifica. Cuando un usuario descarga una actualización a la aplicación, la nueva versión incluirá la última base de datos del catálogo de animales (estática), por lo que no debemos preocuparnos de que esté desactualizada.

Pero, ahora la parte complicada: ¿cómo almacenamos los datos personalizados del usuario (dinámico) de una manera sensata?

Mi primer pensamiento es que la base de datos (dinámica) debe almacenarse en el directorio de documentos para la aplicación, por lo que las actualizaciones de la aplicación no afectan a los datos existentes. ¿Estoy en lo correcto?

Mi segundo pensamiento es que la base de datos personalizada de usuario (dinámica) no está en la misma tienda que el catálogo de animales (estático), no podemos ingenuamente establecer una relación entre la Calificación y las entidades de Notes (en una base de datos) y la entidad Animal (en la otra base de datos). En este caso, me imagino que una solución sería tener una propiedad de cadena "nombreAnimal" en la entidad de Calificación/Notas, y hacerla coincidir en tiempo de ejecución. ¿Es esta la mejor manera de hacerlo, o hay una forma de "sincronizar" dos bases de datos diferentes en Core Data?

+0

@ Shaggy Frog ... Ahora estoy enfrentando el mismo problema. Veo que su solución es la correcta para resolver este problema, pero me gustaría saber si ha descubierto una forma mejor de hacerlo. gracias por la solución de todos modos. es la mejor ayuda que he encontrado hasta ahora. – learner2010

+0

@ user621808 La única solución sería no reconstruir la base de datos cada vez que actualice los datos. En otras palabras, compilarlo exactamente una vez y luego editarlo a mano cada vez que se agreguen/eliminen/editen. –

Respuesta

2

Esto es básicamente cómo terminé resolviendo esto.

Mientras que las respuestas de Amorya y MHarrison eran válidas, tenían una suposición: que una vez creadas, no solo las tablas sino también cada fila en cada tabla serían siempre las mismas.

El problema es que mi proceso para rellenar previamente la base de datos "Animales", utilizando los datos existentes (que se actualiza periódicamente), crea un nuevo archivo de base de datos cada vez. En otras palabras, no puedo confiar en la creación de una relación entre la entidad Animal (estática) y una entidad de Calificación (dinámica) en Datos Básicos, ya que esa entidad puede no existir la próxima vez que regenere la aplicación. Por qué no? Porque no tengo control sobre cómo Core Data está almacenando esa relación detrás de escena. Como es una tienda de respaldo de SQLite, es probable que esté usando una tabla con relaciones de clave externa. Pero cuando regenera la base de datos, no puede asumir nada sobre qué valores obtiene cada fila para una clave. La clave principal para Lion puede ser diferente la segunda vez, si agregué un Lemur a la lista.

La única forma de evitar este problema sería rellenar previamente la base de datos solo una vez y actualizar manualmente las filas cada vez que haya una actualización. Sin embargo, ese tipo de proceso no es realmente posible en mi caso.

Entonces, ¿cuál es la solución? Bueno, dado que no puedo confiar en las relaciones de claves foráneas que Core Data genera, tengo que hacer las mías. Lo que hago es introducir un paso intermedio en mi proceso de generación de base de datos: en lugar de tomar mis datos brutos (que pasa a ser texto UTF-8 pero en realidad son archivos MS Word) y crear directamente la base de datos SQLite con Core Data, presento un intermediario paso: convierto el .txt a .xml. Por qué XML? Bueno, no porque sea una bala de plata, sino simplemente porque es un formato de datos que puedo analizar muy fácilmente. Entonces, ¿qué tiene este archivo XML diferente? Un valor hash que genero para cada Animal, usando MD5, que asumiré es único. ¿Para qué es el valor hash? Bueno, ahora puedo crear dos bases de datos: una para los datos de Animal "estáticos" (para los que ya tengo un proceso) y otra para la base de datos de Calificaciones "dinámica", que crea la aplicación de iPhone y que vive en el directorio Documentos de la aplicación . Para cada Clasificación, creo una pseudo relación con el Animal guardando el valor hash de la entidad Animal. Así que cada vez que el usuario abre una vista detallada de Animal en el iPhone, consulto la base de datos "dinámica" para encontrar si existe una entidad de calificación que coincida con el valor de Animal.md5Hash.

Como estoy guardando este archivo intermedio de datos XML, la próxima vez que haya una actualización, puedo diferirlo del último archivo XML que utilicé para ver qué ha cambiado. Ahora, si se cambió el nombre de un animal, digamos que se corrigió un error tipográfico, revertí el valor de hash para ese Animal in situ. Esto significa que incluso si se cambia un nombre Animal, aún podré encontrar una Calificación coincidente, si existe, en la base de datos "dinámica".

Esta solución tiene otro buen efecto secundario: no necesito manejar ningún problema de migración. La base de datos de animales "estática" que se envía con la aplicación puede permanecer integrada como recurso de la aplicación. Puede cambiar todo lo que quiere. La base de datos de calificaciones "dinámica" puede necesitar migración en algún momento, si modifico su modelo de datos para agregar más entidades, pero en realidad los dos modelos de datos permanecen totalmente independientes.

1

La forma en que lo hago es enviar una base de datos de las cosas estáticas como parte de su paquete de aplicaciones. Al iniciarse la aplicación, compruebe si hay un archivo de base de datos en Documentos. De lo contrario, copie el del paquete de la aplicación a Documentos. A continuación, abra la base de datos desde Documentos: este es el único desde el que lee y edita.

Cuando se produce una actualización, el nuevo contenido estático deberá fusionarse con la base de datos editable del usuario. Cada elemento estático (Animal, en su caso) tiene un campo llamado factoryID, que es un identificador único. En el primer lanzamiento después de una actualización, cargue la base de datos desde el paquete de la aplicación y repita cada Animal. Para cada uno, encuentre el registro apropiado en la base de datos de trabajo y actualice los campos según sea necesario.

Puede haber una solución más rápida, pero dado que el proceso de actualización no ocurre con demasiada frecuencia, el tiempo empleado no debería ser demasiado problemático.

+0

Pero esto requeriría que el proceso que rellene previamente la base de datos no pueda crear una nueva base de datos desde cero cada vez, ¿correcto? Eso es ciertamente posible, pero no tan simple ya que ese proceso ya no es "sin estado". –

1

Almacenar su base de datos SQLite en el directorio de Documentos (NSDocumentDirectory) es ciertamente el camino a seguir. En general, debe evitar los cambios de la aplicación que modifiquen o eliminen las tablas SQL tanto como sea posible (agregar es correcto). Sin embargo, cuando absolutamente tiene que hacer un cambio en una actualización, algo como lo que dijo Amorya funcionaría: abrir el antiguo DB, importar lo que necesite en el nuevo DB y eliminar el anterior.

Como parece que quiere una base de datos estática con una tabla "Animal" que no se puede modificar, simplemente reemplazar esta tabla con actualizaciones no debería ser un problema, siempre y cuando el ID de las entradas no lo haga t cambio. La forma en que debe almacenar datos de usuario sobre animales es crear una relación con una clave externa a una identificación de animal para cada entrada que el usuario cree. Esto es lo que necesitaría para migrar cuando una actualización lo cambie.

+0

También estoy teniendo este problema. Necesito averiguar cómo agregar algunas filas más a la base de datos del usuario.La base de datos v2 con las nuevas incorporaciones para la aplicación va a ser copiado en cualquier instalación nueva, pero tengo que añadir las adiciones a la base de datos SQL en el directorio del usuario para las personas que instalan v1. ¿Cómo puedo hacer eso? He estado buscando por algunas semanas y parece que no puedo encontrar el código para hacerlo. – RyeMAC3

Cuestiones relacionadas