How to get multiple types of objects using a single query in Azure Table Storage?

I’m trying to understand how Azure table storage works to create facebook-style feeds, and I am fixated on how to get posts.

(My questions are almost the same as https://stackoverflow.com/questions/6843689/retrieve-multiple-type-of-entities-from-azure-table-storage , but the link in the answer is broken.)

This is my supposed approach:

  • Create a personal channel for all users of my application, which may contain different types of entries (notification, status update, etc.). My idea is to store them in an Azure table, grouped by partition key for each user.

  • Extract all records in one key and pass them to different views depending on the type of record.

How to request table storage for all types of the same basic type while maintaining their unique properties?

For CloudTableQuery<TElement>a typed object is required, if I specify EntryBaseas a general argument, I do not get the properties specific to writing ( NotificationSpecificProperty, StatusUpdateSpecificProperty) and vice versa.

My objects:

public class EntryBase : TableServiceEntity
{
    public EntryBase()
    {


    }
    public EntryBase(string partitionKey, string rowKey)
    {
        this.PartitionKey = partitionKey;
        this.RowKey = rowKey;
    }
}


public class NotificationEntry : EntryBase
{
    public string NotificationSpecificProperty { get; set; }
}

public class StatusUpdateEntry : EntryBase
{
    public string StatusUpdateSpecificProperty { get; set; }
}

My request for feed:

List<AbstractFeedEntry> entries = // how do I fetch all entries?

foreach (var item in entries)
{

    if(item.GetType() == typeof(NotificationEntry)){

        // handle notification

    }else if(item.GetType() == typeof(StatusUpdateEntry)){

        // handle status update

    }

}
+5
source share
4 answers

Finally, the official way! :)

Take a look at the NoSQL sample that does just that in this link from the Azure Storage Team blog:

Windows Azure Storage 2.0 Client Library Deep Dive Sheets

+5
source

There are several ways to do this, and how you do it depends a little on your personal preferences, as well as on potential performance goals.

  • , . StatusUpdateEntry NotificationEntry, . ( ). "type" ( ), . , ( DTO).

:

[DataServiceKey("PartitionKey", "RowKey")]
public class NoticeStatusUpdateEntry
{
    public string PartitionKey { get; set; }   
    public string RowKey { get; set; }
    public string NoticeProperty { get; set; }
    public string StatusUpdateProperty { get; set; }
    public string Type
    {
       get 
       {
           return String.IsNullOrEmpty(this.StatusUpdateProperty) ? "Notice" : "StatusUpate";
       }
    }
}
  • . , ReadingEntity. XML, , . Jai Haridas Pablo Castro , (. ), , .

, , . . , , , , . - , , , RowKey PartitionKey, , ( , , PK RK).

Edit: Lucifure, - . , .. , - , , .

:

[DataServiceKey("PartitionKey", "RowKey")]   
public class GenericEntity   
{   
    public string PartitionKey { get; set; }   
    public string RowKey { get; set; } 

    Dictionary<string, object> properties = new Dictionary<string, object>();   

    internal object this[string key]   
    {   
        get   
        {   
            return this.properties[key];   
        }   

        set   
        {   
            this.properties[key] = value;   
        }   
    }   

    public override string ToString()   
    {   
        // TODO: append each property   
        return "";   
    }   
}   


    void TestGenericTable()   
    {   
        var ctx = CustomerDataContext.GetDataServiceContext();   
        ctx.IgnoreMissingProperties = true;   
        ctx.ReadingEntity += new EventHandler<ReadingWritingEntityEventArgs>(OnReadingEntity);   
        var customers = from o in ctx.CreateQuery<GenericTable>(CustomerDataContext.CustomersTableName) select o;   

        Console.WriteLine("Rows from '{0}'", CustomerDataContext.CustomersTableName);   
        foreach (GenericEntity entity in customers)   
        {   
            Console.WriteLine(entity.ToString());   
        }   
    }  

    // Credit goes to Pablo from ADO.NET Data Service team 
    public void OnReadingEntity(object sender, ReadingWritingEntityEventArgs args)   
    {   
        // TODO: Make these statics   
        XNamespace AtomNamespace = "http://www.w3.org/2005/Atom";   
        XNamespace AstoriaDataNamespace = "http://schemas.microsoft.com/ado/2007/08/dataservices";   
        XNamespace AstoriaMetadataNamespace = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";   

        GenericEntity entity = args.Entity as GenericEntity;   
        if (entity == null)   
        {   
            return;   
        }   

        // read each property, type and value in the payload   
        var properties = args.Entity.GetType().GetProperties();   
        var q = from p in args.Data.Element(AtomNamespace + "content")   
                                .Element(AstoriaMetadataNamespace + "properties")   
                                .Elements()   
                where properties.All(pp => pp.Name != p.Name.LocalName)   
                select new   
                {   
                    Name = p.Name.LocalName,   
                    IsNull = string.Equals("true", p.Attribute(AstoriaMetadataNamespace + "null") == null ? null : p.Attribute(AstoriaMetadataNamespace + "null").Value, StringComparison.OrdinalIgnoreCase),   
                    TypeName = p.Attribute(AstoriaMetadataNamespace + "type") == null ? null : p.Attribute(AstoriaMetadataNamespace + "type").Value,   
                    p.Value   
                };   

        foreach (var dp in q)   
        {   
            entity[dp.Name] = GetTypedEdmValue(dp.TypeName, dp.Value, dp.IsNull);   
        }   
    }   


    private static object GetTypedEdmValue(string type, string value, bool isnull)   
    {   
        if (isnull) return null;   

        if (string.IsNullOrEmpty(type)) return value;   

        switch (type)   
        {   
            case "Edm.String": return value;   
            case "Edm.Byte": return Convert.ChangeType(value, typeof(byte));   
            case "Edm.SByte": return Convert.ChangeType(value, typeof(sbyte));   
            case "Edm.Int16": return Convert.ChangeType(value, typeof(short));   
            case "Edm.Int32": return Convert.ChangeType(value, typeof(int));   
            case "Edm.Int64": return Convert.ChangeType(value, typeof(long));   
            case "Edm.Double": return Convert.ChangeType(value, typeof(double));   
            case "Edm.Single": return Convert.ChangeType(value, typeof(float));   
            case "Edm.Boolean": return Convert.ChangeType(value, typeof(bool));   
            case "Edm.Decimal": return Convert.ChangeType(value, typeof(decimal));   
            case "Edm.DateTime": return XmlConvert.ToDateTime(value, XmlDateTimeSerializationMode.RoundtripKind);   
            case "Edm.Binary": return Convert.FromBase64String(value);   
            case "Edm.Guid": return new Guid(value);   

            default: throw new NotSupportedException("Not supported type " + type);   
        }   
    }
+2

, , , , , . .

, "dunnry", .

Azure, Lucifure Stash, azure, , / , , .

Lucifure Stash > 64 , , , , , , . http://www.lucifure.com NuGet.com.

Edit: now open source CodePlex

+1
source

Use DynamicTableEntity as the type of object in your queries. It has a dictionary of properties that you can find. It can return any type of entity.

+1
source

All Articles