2

I have an object Record that has a Name and a Theme.

A Theme is a KeyValue pair embedded in a typed class, like "01"-"Sport", "02"-"Home" etc

I have an object like this:

public class DescriptionEntity : TableEntity
{
    public string Description { get; set; }
    public string Key { get { return RowKey; } set { RowKey = value; } }

    public DescriptionEntity() { }
}

public class Theme : DescriptionEntity
{
}

/* The Record has a "string" and a "Theme" property */
public class Record : TableEntity
{
    [...]
    public string Name { get; set; }
    public Theme Theme { get; set; }
}

The problem is when I try to load that record from the Azure Tables, like this:

var record = await repository.GetTableEntityAsync<Record>(id, RecordConst.RecordPartitionKey);

// ..........................
public async Task<T> GetTableEntityAsync<T>(string rowKey, string partitionKey) where T : ITableEntity, new()
{
    var table = GetTable<T>();

    TableQuery<T> query = new TableQuery<T>().Where(
        TableQuery.CombineFilters(
           TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, partitionKey),
           TableOperators.And,
           TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.Equal, rowKey))).Take(1);

    var result = new T();

    TableContinuationToken continuationToken = null;
    do
    {
        Task<TableQuerySegment<T>> querySegment = table.ExecuteQuerySegmentedAsync(query, continuationToken);
        TableQuerySegment<T> segment = await querySegment;
        result = segment.FirstOrDefault();
        continuationToken = segment.ContinuationToken;
    } while (continuationToken != null);

    return result;
}

I obtain the record.Name, but the record.Theme remains always "null", does not load from the "Record" table, that is like:

Partition Key Name    Theme
"record"  "x" "test"  "01"

also in my "Theme" table I have

Partition Key  Description
"en"      "01" "Sport"

I tried to add to the "Theme" class the constructors

public class Theme : DescriptionEntity
{
    public Theme() : base() { }
    public Theme(string key) : base(key) { }
}

but this didn't change the result...

Is there a way to explicitly say "take the string "Theme" and use new Theme(string) to create the Theme property"

serge
  • 13,940
  • 35
  • 121
  • 205

3 Answers3

1

As you may already know that Azure Tables is a Key/Value store. However the main point to consider is that the Value can be of following predefined types: String, Int32, Int64, DateTimeOffset, Double, GUID and Binary.

In your case, the value for attribute Theme is of type Theme which is not one of the supported types and hence Storage Client Library is not deserializing it and thus you're getting null value.

One possible solution would be to store this attribute's value in string format by using JSON serializer and deserialize it in your application when you fetch it.

Gaurav Mantri
  • 128,066
  • 12
  • 206
  • 241
  • I don't use the JSON, because I have already Themes in a table, I just need the "01" to identity the Theme... is there a way to explicitly say "take the string "Theme" and use `new Theme(string)` to create the class" – serge Jul 24 '17 at 09:51
  • If your themes are already stored in the table, you can query that table and then you can get the Theme object. You will have to make 2 requests to Table Storage though. – Gaurav Mantri Jul 24 '17 at 09:54
  • I load my themes in a list of Theme using a query. But the problem in the Record that does not take the "Theme" property. – serge Jul 24 '17 at 09:56
  • Could you please provide an example how to make that 2 requests because is not very clear for me how to achieve it. – serge Jul 26 '17 at 05:32
0

I found a "simple" solution to use string instead of Theme as type of the Theme property...

But I'd like to know if there are some ways to custom control the serialization/loading from tables into objects...

serge
  • 13,940
  • 35
  • 121
  • 205
0

Azure Table Storage Client SDK v8.0.0.0 has introduced support to write and read complex objects with complex properties with 2 new methods on TableEntity class.

To insert your complex object, you flatten it by TableEntity.Flatten method: https://learn.microsoft.com/en-us/dotnet/api/microsoft.windowsazure.storage.table.tableentity.flatten?view=azurestorage-8.1.3

and insert flatened object to azure table storage as DynamicTableEntity.

Once you read it back, you use TableEntity.ConvertBack<TypeOfYourComplexObject>

https://learn.microsoft.com/en-us/dotnet/api/microsoft.windowsazure.storage.table.tableentity.convertback?view=azurestorage-8.1.3#Microsoft_WindowsAzure_Storage_Table_TableEntity_ConvertBack__1_System_Collections_Generic_IDictionary_System_String_Microsoft_WindowsAzure_Storage_Table_EntityProperty__Microsoft_WindowsAzure_Storage_OperationContext_

to convert the flattened entity to its original complex form. Apart from Collection and IEnumerable types, all other types of properties complex, simple, class, struct, enum etc. are supported

Flatten method will flatten your entire Record object into a flat structure so in your example complex Theme property on the record object will be flatenned to 2 key value pairs with corresponding names Theme_Description and Theme_Key. Their values will be the EntityProperties created from their string values. So once the record object is written to table storage you can individually access (read, project, update) Theme_Description or Theme_Key properties on this record entity.

You can also have a look at the article I wrote about writing complex, multi-hierarchial objects into azure table storage: https://doguarslan.wordpress.com/2016/02/03/writing-complex-objects-to-azure-table-storage/

In addition to this if you want a custom conversion logic ie. from a string Key property to a full Theme property I recommend you to have a look at overloaded version of Retrieve method where you can specify a custom EntityProperty converter. https://learn.microsoft.com/en-us/dotnet/api/microsoft.windowsazure.storage.table.tableoperation.retrieve?view=azurestorage-8.1.3#Microsoft_WindowsAzure_Storage_Table_TableOperation_Retrieve__1_System_String_System_String_Microsoft_WindowsAzure_Storage_Table_EntityResolver___0__System_Collections_Generic_List_System_String__

Dogu Arslan
  • 3,292
  • 24
  • 43
  • So, you mean, say I have 3 themes and thousands of records. Each record will store its Theme as a JSON in the table instead of just the Theme key as string? What if tomorrow, say the first Theme change its Text description? The saved records will have the obsolete Theme name? – serge Jul 26 '17 at 05:29
  • no not as Json. Flatten method will flatten your entire Record object into a flat structure so in your example complex Theme property on the record object will be flatened to 2 key value pairs with corresponding names Theme_Description and Theme_Key. Their values will be the EntityProperties created from their string values. – Dogu Arslan Jul 26 '17 at 10:09
  • ok, that does not change the problem that the Theme "Names" will be "serialized"... so if my application is multilingual by eg... – serge Jul 26 '17 at 10:21