¿Existe una manera eficiente de sincronizar datos en una base de datos local en una aplicación de Android y un servidor remoto?

Tengo cierta experiencia con la sincronización de datos entre la aplicación de Android y el servidor remoto para una aplicación de estilo crm para un cliente donde los datos debían sincronizarse entre muchos dispositivos y una sola aplicación web. La aplicación era una aplicación nativa de Android y la aplicación web estaba escrita en C # con The Official Microsoft Asp.net MVC 5 y Web Api. Los ORM que utilicé fueron Entity Framework en el lado web y SugarORM en el lado de Android. Diciendo todo eso, pero nada de eso importa realmente.

Cómo lo hice fue como sigue. Tanto en la aplicación como en la aplicación web utilicé herramientas ORM para construir y acceder a la base de datos. Al definir las entidades, el cliente, el pedido, el usuario, etc., tuve una clase base con algunos campos principales para cada entidad, ID, CreatedDate, UpdatedDate y en la aplicación web tuve un campo adicional, SyncedDate. En la aplicación de Android tenía un campo adicional, ServerID, hablaré un poco más sobre eso más adelante.

Luego tuve una API de descanso y una clase de controlador base abstracta (estaba usando un marco de estilo mvc) y, junto con la tipificación genérica, esto podría extenderse una vez para cada una de las entidades que quería sincronizar. En la clase base había implementado los métodos para manejar la publicación y obtener solicitudes, también podría haber implementado un controlador de eliminación, pero no lo necesitaba, ninguno de los datos se eliminó realmente de este sistema, simplemente se ocultó a la vista.

Cuando se ejecuta la tarea de sincronización de fondo, para cada entidad, la aplicación de Android almacena localmente la última hora sincronizada, que se actualiza después de cada sincronización exitosa de cada entidad. La aplicación realizó una solicitud de obtención de la URL apropiada para cada entidad, proporcionando la última fecha sincronizada de esa entidad. El controlador de solicitud de obtención luego recogió la última hora sincronizada y devolvió una matriz de ese tipo de entidad donde el SyncedDate de cada uno de los registros fue mayor que el proporcionado por la aplicación en la solicitud. Cuando llegaron a la aplicación de Android, no almacené las filas nuevas / actualizadas en la base de datos de inmediato para poder consultar los elementos actualizados desde la última sincronización en la aplicación, para publicar de nuevo en el servidor. Una vez que obtuve la lista de registros actualizada en la aplicación para volver a publicarla en el servidor, para cada uno de los que hice una solicitud de publicación al servidor, la aplicación web luego agregó / actualizó los registros a la base de datos en función del campo ServerID proporcionado por las entidades en el lado de Android. Luego, la aplicación de Android almacenó la marca de tiempo actual de Unix para usar en la próxima ejecución de sincronización.

Un problema que enfrenté fue asignar Ids a nuevas entidades, ya que podrían crearse tanto en la aplicación web como en la aplicación de Android. Resolví esto usando un GUID / UUID. La base de datos Azure Sql en el lado web admitía el tipo de datos GUID, por lo que este era el tipo de mi campo ID de la clase de entidad base para entidades sincronizadas. En el lado de Android, el tipo de datos UUID no era compatible con el SQLite db, por lo que tenía que almacenarse como una cadena en el campo ServerID, no utilicé este campo de la cadena ServerID como clave principal porque no me gustó la idea de usando una cadena como clave principal, pensé que la indexación sería muy lenta. Tanto en el lado web como en el lado de Android, el GUID / UUID se asignó al crear una nueva entidad.

Otro problema que enfrenté fue que estaba usando la misma implementación del controlador get para cada entidad, lo que significaba que todos los datos tenían que ser devueltos para todas las entidades. Esto estaba bien para mi entidad de cliente, pero para la entidad de pedido, por ejemplo, solo quería que los pedidos de cada usuario fueran devueltos por la solicitud de obtención. Resolví esto definiendo un método en la clase de controlador base rest que tenía que ser implementado por cada controlador para cada entidad. Lo llamé getAdditionalFiltersForGetRequest (nombrar cosas es difícil). Entity Framework le permite usar expresiones linq lambda para generar consultas a la base de datos al pasar y devolver un objeto de tipo IQueriable donde T es el tipo genérico que se define al extender la clase base. Esto me permitió hacer cosas como query.Where (i => i.UserId == userId), por ejemplo, para la entidad de pedido, pero las clases base obtienen el manejador de solicitudes aún podría agregar la sincronización central donde las cláusulas al objeto IQueryable.

Pido disculpas por mi terrible intento de inglés, fin de semana muy ocupado y estoy muy cansado, además, he escrito esto desde mi teléfono durante un viaje en coche de 5 horas. Actualizaré al día siguiente o 2 con algunos fragmentos de código para el contexto y algunos enlaces de recursos que encontré útiles. Implementé esta sincronización como parte de un sistema para un cliente para mi proyecto final en la universidad aquí en Irlanda del Norte. Me encantaría recibir comentarios y comentarios sobre la implementación una vez que obtenga algunos fragmentos de código, especialmente me gustaría ver otras implementaciones de esto.

¡Gracias si has llegado hasta aquí!