I'm developing an application, that allows using dictionaries (e.g. English - German or Country - Capital). There are just 2 very plain tables:
int Id, string Title //PartitionKey="SomeConstString", Rowkey=Id.ToString()
int DictionaryId, string Word, string Meaning //PartitionKey="D" + DictionaryID, Rowkey=Word
I can add articles, but when trying to delete I get the following problem: in every dictionary one or two articles are not deleted. Instead I get ResourceNotFoundException. There is absolutely nothing special about those articles (e.g. Russia - Moscow).
When I try to add articles with same PartitionKey and RowKey I get EntityAlreadyExistsException. I installed "Cloud Storage Studio" and found out that those entities are really still in table. I tried to delete them manually but got the same ResourceNotFoundException
in storage studio that I was getting in code. So if I add 100 articles and then try to delete them (in code or in studio like Ctrl+A -> Delete), 99 (or sometimes 98) are deleted and others are not. I'm using development storage emulator. Here is how I remove
articles (I tried different approaches, result is still the same):
Can anyone tell me what can possibly be wrong with this? I can attach a screenshot from storage studio if needed.
Update: Here is a screenshot.
Only this one selected record is not deleted in this table. I really can't imagine, what is so special about it. I tried other dictionary and 2 articles were not deleted from it either. I tried using Detach, exception is then no longer thrown, but entity still
remains in the table. I can use IgnoreResourceNotFoundException=true, but it still won't remove the record. There is a possibility that I'll need to add an entity with same PK&RK in future and this will fail ('EntityAlreadyExists' exception)
What is the partition key of rows that can't be deleted? Also try to detach the object before deleting it (TableServiceContext.Detach(...))change TableServiceContext.IgnoreResourceNotFoundException to true. And please attach the screenshot.
You can try opening the emulator database and navigating to the offending row in SQL Server Management Studio.
Then try locating the row, using a SELECT statement, and seeing how different it is from the others. Maybe even attempting a delete.
I followed the advice to check devstorage .mdf database and I think I found the problem, there was a space character (0x20, ' ') in the end of the word which is RowKey. So it was say 'RowKey1 '. I removed space and now everything is fine in devstorage
too (it was not a problem in real environment). However it is rather confusing that spaces are treated correctly inside the key (say 'Row Key 1' can be used without errors) but cause such behaviour if are trailing characters (or maybe leading too). I've read
about 'Characters Disallowed in Key Fields', but spaces were not mentioned there. I guess I should use Trim() for my strings before using them as keys.
I am glad you found the issue using the technique I suggested. This is very useful information!
I suspect that because the data is transported serialized in XML over HTTP, there is a huge propensity of errors such as this resulting
from the way leading/trailing spaces in the XML, are interpreted on both the client and the service. Yes, using trim() is a good idea when writing to table storage, especially the key.
I have written an azure table storage client,
www.lucifure.com, and this is really a good opportunity for me to verify how my client behaves under the same circumstances. Depending on the server’s implementation, it may be a good idea for a client to auto handle trimming
keys or columns. So, thanks for posting this issue, I will look deeper into the table storage service to satisfy my curiosity and improve my product.
Digging deeper into the table storage service behavior, both using the Microsoft Storage Client and without, I observed the following.
The Azure Storage client will send an xmls:space="preserve" for a key or string column which contains leading or trailing spaces. However, the server does not respect ‘preserving’ a column containing
only spaces but will store it as a non-null string column of length 0.
In XML, xml:space="preserve" is used to indicate if white spaces should be preserved. According to this document, it is only a signal of intent and applies only to whitespaces in text nodes. That is nodes which contain only white space (CR, LF, tab and space).
If any other character is present, it is not considered a white space node. http://www.xmlplease.com/xml/xmlspace/ .
My testing, using Lucifure Stash (www.Lucifure.com) which does
not use the Microsoft Storage Client but instead writes directly to the REST API concluded that, on a request, the Table Storage does not cares whether the 'preserve' is included or not, and by default will always, preserve leading and trailing
spaces. However, the table storage service, on response, will send back a 'preserve' if there are leading or trailing spaces.