0

Backgroung

Assuming I have an Azure Table Entity

class MyEntity : TableEntity
{
    public string LongString { get; set; }
    public bool IsCompressed { get; set; }
}

And if the LongString > 64KB (Azure limitation for property), I want to save the LongString compressed. For this I have 2 functions of Compress(string) and Decompress(string)

Currently, before every insert I'm checking the length of LongString and if it's > 64KB, I'm setting LongString = Compress(LongString) and IsCompressed = true. The opposite after every Azure get operation.

I want to hide the option of compression from the entire code and to have the compression and decompression to be self contained in the MyEntity class.

Question

Is there an option to make custom operation before and after getting and setting entities from azure table? Something like ...

class MyEntity : TableEntity
{
    public string LongString { get; set; }
    public string IsCompressed { get; set; }

    public override void BeforeInsert()
    {
        if (LongString.Length > 64KB)
        {
            LongString = Compress(LongString);
            IsCompressed = true;
        }
    }

    public override void AfterGet()
    {
        if (IsCompressed)
        {
            LongString = Decompress(LongString);
            IsCompressed = false;
        }
    }
}
motcke
  • 438
  • 6
  • 17
  • 1
    One minor off topic comment: Given Azure uses UTF16 to encode the data and thus uses 2 bytes to save each byte of data you provide, the limit is actually 32KB instead of 64KB. Thought I should mention that. – Gaurav Mantri Sep 22 '16 at 10:50

3 Answers3

1

A possibility could be something like the following code:

public bool IsCompressed;

public string StoredString { get; set; }

private string longString;

[IgnoreProperty] 
public string LongString
{
    get
    {
        if (this.longString == null)
        {
            if (IsCompressed)
            {
                this.longString = DeCompress(StoredString);
            }
            else
            {
                this.longString = StoredString;
            }
        }
        return this.longString;
    }
    set
    {
        if (longString != value)
        {
            this.longString = value;
            if (this.longString.Length > 64KB)
            {
                IsCompressed = true;
                this.StoredString = Compress(this.longString);
            }
        }
    }
}

But ask yourself if it's not easier to always save a compressed string.

Pascal Naber
  • 1,092
  • 8
  • 14
  • 1. My problem with this solution is that I'll have 2 properties with the same name [L/l]ongString, and I won't know which is the decompressed one. 2. The reason for not compressing allways is for readability in azure table applications when it's not too long (most of the time). – motcke Sep 22 '16 at 10:50
  • Ok, that seems a valid reason. – Pascal Naber Sep 22 '16 at 10:53
  • this answer is the best one because it decompresses the value if needed only – Andrzej Martyna Jan 25 '19 at 11:56
1

Found a solution using the ReadEntity and WriteEntity functions.

class MyEntity : TableEntity
{
    public string LongString { get; set; }
    public bool IsCompressed { get; set; }

    public override void ReadEntity(IDictionary<string, EntityProperty> properties, OperationContext operationContext)
    {
        base.ReadEntity(properties, operationContext);

        if (IsCompressed)
        {
            LongString = Decompress(LongString);
            IsCompressed = false;
        }
    }

    public override IDictionary<string, EntityProperty> WriteEntity(OperationContext operationContext)
    {
        if (LongString.Length > 64KB)
        {
            LongString = Compress(LongString);
            IsCompressed = true;
        }

        return base.WriteEntity(operationContext);
    }
}
motcke
  • 438
  • 6
  • 17
1

You do not need any of that complexity you can just simply create computed properties to write to table storage. And you do not need multiple properties either. Hence no need to have a second property with an IgnoreProperty attribute. I typed below in text editor but this should give you the idea.

private string longString;

public bool IsCompressed { get; set; }

public string LongString
{
    get
    {
        return IsCompressed ? DeCompress(longString) : longString;
    }
    set
    {
       if (String.IsNullOrWhiteSpace(value) || value.Length < 64KB)
       {
           IsCompressed = false;
           longString = value;
       }
       else (value.Length > 64KB)
       {
           IsCompressed = true;
           longString = Compress(value);
       }
    }
}
Dogu Arslan
  • 3,292
  • 24
  • 43