Room unexpected behavior when working with BLOB & TEXT - sqlite

I am migrating my app's SQLite helper to Room. Basically what I am doing is just copying data from old SQLite database to Room, so due to schema mismatch I need to provide migration. I am having this issue with BLOB data in Room.
I have below simple model
class NewCourse {
var weekday: Array<String> = arrayOf()
}
I also have TypeConverter as
#TypeConverter
fun toArray(concatenatedStrings: String?): Array<String>? {
return concatenatedStrings?.split(",".toRegex())?.dropLastWhile { it.isEmpty() }?.toTypedArray()
}
#TypeConverter
fun fromArray(strings: Array<String>?): String? {
return strings?.joinToString(",")
}
Within my old appdatabase.db database I have a corresponding table Course with a field weekday which has a type BLOB.
Well, because of my TypeConverter in room database I will have weekday with a type TEXT. While migrating I running below SQL script.
INSERT INTO NewCourse (weekday) SELECT weekday FROM Course
As weekday from Course table is BLOB type and in SQL you can basically store anything to anything, am I expecting it will copy BLOB-typed weekday in Course to TEXT-typed weekday in NewCourse.
Well at first I was expecting some error due to type mismatch. But "fortunately", but not expectedly, Room doesn't throw any exception and it gets value of BLOB and copies as TEXT.
My first question was why it is working? i.e. how it's copying the TEXT value of BLOB to my newly created table?
I never cared about it, as it was working perfectly, until I did some testing with Robolectic.
Unfortunately, I am getting error if I start testing with Robolectic. After copying data in my migration, when I query for NewCourse I am getting SQL error of
android.database.sqlite.SQLiteException: Getting string when column is blob. Row 0, col 10
So, I suppose here it is copying the data as BLOB and when querying for weekday it is throwing an exception as getWeekDay calls getString of cursor.
My second question would be "Why while testing with Robolectic it is not working as it is working with just running the app?"
I also tested the queries with just Sql not involving Android, and over there it copies the BLOB as BLOB even though the type of weekday at NewCourse is TEXT as expected.

Robolectric is a testing library for android applications. The keyword here is testing and by that it means there shouldn't be any exception. Robolectric showing you error maybe because of some android devices may throw exception so your application will crash. Try checking your logs while your application running. Maybe you are missing some warnings.

Related

How do I make a query equalto with a long value?

I tried to make a query from real time database using equalTo().
database.getReference(verifiedProductsDb.dbPartVerifiedProducts).order By Child(verifiedProductsDb.barcode).equalTo(b.toLong()).get().addOnCompleteListener {
but android studio gives out:
None of the following functions can be called with the argument supplied.
equalTo(Boolean) defined in com.google.firebase.database.Query
equalTo(Double) defined in com.google.firebase.database.Query
equal To(String?) defined in com.google.firebase.database.Query
Despite the fact that using setValue, long values are written to the same database quite successfully and without problems.
The Realtime Database API on Android only has support for Double number types. The underlying wire protocol and database will interpret the long numbers correctly though, so you should be able to just do:
database.getReference("VerifiedProducts")
.orderByChild("barcode")
.equalTo(b.toLong().toDouble()) // 👈
.get().addOnCompleteListener {
...

How to overwrite sqlite database for existing users in a Xamarin Forms app?

We have a Xamarin Forms app.
We have a few existing users which had been using the app since last year where the database file name is MyAppName.db
Our new app strategy requires us to include the .db (Sqlite) along with the app to ensure we can include persistent information and does not require internet when you install the app, meaning we hope to overwrite the db file for existing users.
After we publish this new change where the database file is now MyNewDbFile.db, our users complain that they do not see any data, the app does not crash tough.
We capture error reports and we can see a common error in the our tool stating about "row value missused", a quick search indicates the value are not present and so the "SELECT * FROM TABLE WHERE COLUMNAME" query does not work causing the exception.
We can confirm we are using
Xamarin.Forms version 4.5.x
sqlite-net-sqlcipher version 1.6.292
We do not have any complex logic and cannot see a very specific reason causing this as this is not produced when we test our apps from the Alpha channel or the TestFlight.
We investigated the heart of the problem and can confirm that the troublemaker is the device Culture information.
We have been testing with English as the device language, however the minute the app is used by folks with any other language except English the query causes exception.
We make use of the Xamarin Essentials library to get device location (which is optional).
The latitude and longitude returned are culture specific.
So if you are using a Spanish language on device, the format for the Latitude and Longitude information is a , (comma) and NOT a . (dot).
That is, a Latitude value is something similar to 77.1234
where it is separated by a . (dot)
However for users with different region settings on device, the format would change to
77,1234 as value where it is separated by a , (comma).
The query requires us to have the values as string and that when not separated by a . (dot) fails to execute:
Query:
if (deviceLocation != null)
queryBuilder.Append($" ORDER BY((Latitude - {deviceLocation.Latitude})*(Latitude - {deviceLocation.Latitude})) +((Longitude - {deviceLocation.Longitude})*(Longitude - {deviceLocation.Longitude})) ASC");
Where the deviceLocation object is of type Xamarin.Essentials.Location which has double Latitude and Longitude values but when used as a string or even if you explicitly do deviceLocation.Latitude.ToString(), it would return the formatted values as per the device CultureInfo.
We can confirm that the problem is due to a mismatch of the format type and causing the query to throw an exception and in return making the experience as if there is no data.

Azure Cosmos DB Entity Insert and Data Explorer Error

Just this morning when trying to view the Data Explorer UI for an Azure Cosmos DB table the window is totally blank and I see no rows (the table should not be empty). The only connection to this table is a Python script that pushes in simple rows with only a few variables however this has also stopped working just this morning.
I am still able to connect to the table service properly and I've even been able to create a new table through my Python script. However, as soon as I call table_service.insert_or_replace_entity('traps', task) ('traps' is the name of my table and task is the row I'm trying to push up) I receive back an HTTP Error 400. The request URL is invalid.
For reference, my connection in Python is as follows where Account_Name = my personal account name and Account_Key = my personal account key.
table_service = TableService(connection_string="DefaultEndpointsProtocol=https;AccountName=Account_Name;AccountKey=Account_Key;TableEndpoint=https://Account_Name.table.cosmosdb.azure.com:443/;")
for i in list(range(0,len(times))):
print(len(tags))
print(len(times))
print(len(locations))
task = {'PartitionKey': '1', 'RowKey': '{}'.format(tags[i]),'Date_Time' : '{}'.format(times[i]), 'Location' : '{}'.format(locations[i])}
table_service.insert_or_replace_entity('traps', task)
UPDATE
In reference to the HTTP Error 400 I discovered that I was trying to push a \n at the end of each of the tags string (i.e. tags[0] = 'ab123\n'). Stripping out the \n has resolved the HTTP 400 error but I am now receiving The specified resource does not exist. message when I attempt to upload which makes more sense as at why my Data Explorer is blank. I have tried uploading to a new table but its the same thing.
Second Update
Silly mistake on resource not found error was that my table is called "Traps" not "traps". Data appears to be uploading correctly now on the API side. However, the table is still not displaying at all in the data explorer page of the Azure portal. If anyone has insight on this it would be appreciated because the explorer is super helpful while we are still in development.
Third Update
I am able to connect to the table/database through Python and query data effectively. It all seems to be in there and up to date. The only thing I'm left unsure about is why the Data Explorer is not displaying properly. Aside from that, my recommendation is to obviously check your capital letters (my usual mistake haha) and DO NOT try to push up line feeds (\n) in the task/payload.
Want to provide an official update and response to your issue. This issue is being Hotfixed with an ETA rolled out by Monday (09/24/2018).

getting 409 error when trying to call table.CreateIfNotExists() for the first time

When starting my program for the first time since the associated table has been deleted I get this error:
An exception of type 'Microsoft.WindowsAzure.Storage.StorageException' occurred in Microsoft.WindowsAzure.Storage.dll but was not handled in user code
Additional information: The remote server returned an error: (409) Conflict.
However if I refresh the crashed page the table will successfully create.
Here is the code just in case:
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
Microsoft.WindowsAzure.CloudConfigurationManager.
GetSetting("StorageConnectionString"));
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
CloudTable table = tableClient.GetTableReference("tableTesting");
table.CreateIfNotExists();
I don't really understand how or why I'd be getting a conflict error if there's nothing there.
These errors appear elsewhere in my code as well when I'm working with blob containers, but I can't reproduce them as easily.
If you look at the status codes here: http://msdn.microsoft.com/en-us/library/azure/dd179438.aspx, you will notice that you get 409 error code in two scenarios:
Table already exists
Table is being deleted
If I understand correctly, table.CreateIfNotExists() only handles the 1st situation but not the 2nd one. Please check if that is not the case in your situation. One way to check this would be to see details of Storage Exception. Somewhere you should get the code which would match with the link I mentioned above.
Also one important thing to understand is that when you delete the table, it is actually marked for deletion and is actually deleted through a background process (much like garbage collection). If you try to create a table between these two steps, you will get the 2nd error.

How to get error code returned by query using MySQL in Asp.Net

I am working with MySQL in my .net web app with the help of MySQL connector 5.0.9.0.
I am getting data from a web service and inserting it in local database. I only want to insert unique rows in my local database. I came to know that when an duplication occurs, MySQL returned an error code: 1062.
All i want to know that how i could i get this code in a variable and check it against my condition like:
if(errorCode == "1062")
{
Response.Write("Record already exists");
}
else
{
// add the record to database
}
Thanx in advance
Have a look at MySqlException class members. There is a Number property - Gets a number that identifies the type of error.
MySqlException Class.

Resources