SLAB Querying Azure Table

Topics: Semantic Logging Application Block
Jul 25, 2014 at 9:45 AM
Is there a way to query EventEntries stored in Azure Table Storage.
The EventEntry hasn't a parameterless constructor so I'm not able to convert the dynamic table entity back into a EventEntry.

I just would like to query my Events.

Is there a way I can accomplish this?

Code I was trying:
        string eventFilter = TableQuery<EventEntry>.GenerateFilterCondition("EventId", QueryComparisons.Equal, "3002");
        TableQuery<EventEntry> query = new TableQuery<EventEntry>().Where(eventFilter );
        var s = table.ExecuteQuery<EventEntry>(query);
Jul 30, 2014 at 4:54 PM
Edited Jul 30, 2014 at 4:56 PM
The EventEntry class is not intended to be used to query Azure Storage. The Azure Table has dynamic columns so the the schema of the table depends on the event payloads that are written into the table. The payload is application specific. You could query it and deserialize the JSON or query the specific columns that you are interested in.

One way to do it would be to use DynamicTableEntity similar to this post:
    public class MyEventEntry
    {
        public int? EventId { get; set; }

        public DateTimeOffset? EventDate { get; set; }

        public string Payload { get; set; }
    }

    CloudStorageAccount storageAccount = CloudStorageAccount.DevelopmentStorageAccount;
    CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
    CloudTable table = tableClient.GetTableReference("SLABLogsTable");

    TableQuery<DynamicTableEntity> projectionQuery =
        new TableQuery<DynamicTableEntity>()
        .Where(TableQuery.GenerateFilterConditionForInt("EventId", QueryComparisons.Equal, 1))
        .Select(new string[] { "EventId", "EventDate", "Payload" });

    EntityResolver<MyEventEntry> resolver = (pk, rk, ts, props, etag) =>
    {
        MyEventEntry entry = new MyEventEntry()
        {
            EventId = props["EventId"].Int32Value,
            EventDate = (DateTimeOffset)props["EventDate"].DateTimeOffsetValue,
            Payload = props["Payload"].StringValue
        };

        return entry;
    };

    foreach (var myEventEntry in table.ExecuteQuery(projectionQuery, resolver, null, null))
    {
        Console.WriteLine(myEventEntry.EventId ?? 0);
        Console.WriteLine(myEventEntry.EventDate ?? null);
        Console.WriteLine(myEventEntry.Payload);
    }

That should work but usually I would see that approach as being more ad-hoc. If you wanted something a bit more organized and reusable then you could create a class that implements ITableEntity. An example of this approach is:
    CloudStorageAccount storageAccount = CloudStorageAccount.DevelopmentStorageAccount;
    CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
    CloudTable table = tableClient.GetTableReference("SLABLogsTable");

    TableQuery<AzureEventEntry> query =
        new TableQuery<AzureEventEntry>()
        .Where(TableQuery.GenerateFilterConditionForInt("EventId", QueryComparisons.Equal, 1));

    foreach (var myEventEntry in table.ExecuteQuery<AzureEventEntry>(query))
    {
        Console.WriteLine(myEventEntry.EventId ?? 0);
        Console.WriteLine(myEventEntry.EventDate ?? null); 
        Console.WriteLine(myEventEntry.Payload);
    }

    public class AzureEventEntry : ITableEntity
    {
        public string ETag { get; set; }

        public string PartitionKey { get; set; }

        public string RowKey { get; set; }

        public DateTimeOffset Timestamp { get; set; }


        public int? EventId { get; set; }

        public int? Level { get; set; }

        public int? Opcode { get; set; }

        public int? Task { get; set; }

        public int? Version { get; set; }

        public DateTimeOffset? EventDate { get; set; }

        public string Payload { get; set; }

        public string ProviderName { get; set; }

        public string InstanceName { get; set; }

        public Guid? ProviderId { get; set; }

        public string FormattedMessage { get; set; }

        public long? Keywords { get; set; }

        public int? ProcessId { get; set; }

        public int? ThreadId { get; set; }

        public Guid? ActivityId { get; set; }

        public Guid? RelatedActivityId { get; set; }

        public void ReadEntity(IDictionary<string, EntityProperty> properties, OperationContext operationContext)
        {
            foreach(var key in properties.Keys)
            {
                switch (key)
                {
                    case "EventId":
                        this.EventId = properties[key].Int32Value;
                        break;

                    case "Keywords":
                        this.Keywords = properties[key].Int64Value;
                        break;

                    case "ProviderId":
                        this.ProviderId = properties[key].GuidValue;
                        break;

                    case "ProviderName":
                        this.ProviderName = properties[key].StringValue;
                        break;

                    case "InstanceName":
                        this.InstanceName = properties[key].StringValue;
                        break;

                    case "Level":
                        this.Level = properties[key].Int32Value;
                        break;

                    case "Opcode":
                        this.Opcode = properties[key].Int32Value;
                        break;

                    case "Task":
                        this.Task = properties[key].Int32Value;
                        break;

                    case "Version":
                        this.Version = properties[key].Int32Value;
                        break;

                    case "ProcessId":
                        this.ProcessId = properties[key].Int32Value;
                        break;

                    case "ThreadId":
                        this.ThreadId = properties[key].Int32Value;
                        break;

                    case "EventDate":
                        this.EventDate = properties[key].DateTimeOffsetValue;
                        break;

                    case "Payload":
                        this.Payload = properties[key].StringValue;
                        break;

                    case "FormattedMessage":
                        this.FormattedMessage = properties[key].StringValue;
                        break;

                    case "ActivityId":
                        this.ActivityId = properties[key].GuidValue;
                        break;

                    case "RelatedActivityId":
                        this.RelatedActivityId = properties[key].GuidValue;
                        break;
                }
            }
        }

        public IDictionary<string, EntityProperty> WriteEntity(OperationContext operationContext)
        {
            throw new NotImplementedException();
        }
    }

The code above extracts all of the standard columns from the azure table. If you are interested in extracting payload information then you would have to implement that yourself. e.g. change AzureEventEntry to AzureEventEntry<T> where T is the payload type.

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to