【问题标题】:Linq command to find differences in Azure Table Storage entries用于查找 Azure 表存储条目差异的 Linq 命令
【发布时间】:2015-09-30 21:44:50
【问题描述】:

我有一个 Azure Table Storage 表,其结构如下:

id    date_changed    entity_1    entity_2
 1      May 1 2015        true       false
 2      May 2 2015       false        true
 3      May 3 2015       false       false
 4      May 4 2015        true       false
 5      May 5 2015       false        true
 6      May 7 2015        true       false

我正在尝试找到一种方法来仅提取 entity_1 随时间变化的那些记录 (date_changed)。 例如,如果我想返回 entity_1false → truetrue → false 更改为 date_changed 增加的记录:

 2      May 2 2015        false      true
 4      May 4 2015        true       false
 5      May 5 2015        false      true
 6      May 7 2015        true       false

或者entity_2

 2      May 2 2015        false      true
 3      May 3 2015        false      false
 5      May 5 2015        false      true
 6      May 7 2015        true       false

我当然可以通过循环来做到这一点,但这不会真正扩展,因为我必须遍历我的所有记录,并且随着我的表增加记录,这似乎是不可行的。

有没有办法创建一个 Linq 查询来查询表存储以仅返回 entity_1entity_2 随着 date_changed 增加而变化的那些记录?

【问题讨论】:

  • 随着日期的变化,您是否为每个实体插入一条记录?我的意思是,今天是 7 月 12 日。随着时钟到达 7 月 13 日,您是否在表中为所有具有当前状态(真或假)的实体插入一条新记录?随着时间的推移,如果实体状态发生变化,您会更新这些实体吗?然后第二天,你又插入新记录?另请告诉我们您的 PartitionKey/RowKey 值。
  • 记录不一定每天都插入,但多条记录不会在同一天插入(即,可能每天插入,也可能每隔一天插入,等等)。 PartitianKey 是一个用户 ID(所以假设上面的例子都有相同的 PartitianKeyRowKey 是一个简单的 GUID
  • 这里有一个想法:你使用实体 id 作为分区键和逆时间(最大时间 - 当前日期)作为行键。因此,每个实体最终将位于不同的分区中,并且最近的更新将始终位于顶部。每当您添加新的更新时,都要有一个额外的字段作为更改指标。您对最新更新的访问将非常高效。一组分区之间的查询将具有高吞吐量。

标签: .net azure azure-table-storage


【解决方案1】:

没有办法通过键值 NoSQL 数据库服务(如 Azure Table)以可扩展的方式实现请求的功能。我推荐的解决方案是创建两个新表,Entity1TransitionTable 和 Entity2TransitionTable。该提议是在 Azure 表存储相对便宜的前提下动态检测转换并维护这些表中的转换列表。此解决方案假定应用程序始终可以跟踪 ID 值并且它始终递增 1。

  public class LogEntry : TableEntity
  {
     public LogEntry() { }
     public LogEntry(string userid, int id, string date, bool entity1, bool entity2)
     {
        PartitionKey = userid;
        RowKey = id.ToString();
        Id = id;
        Entity1 = entity1;
        Entity2 = entity2;
        Date = date;
     }
     public int Id { get; set; }
     public string Date { get; set; } 
     public bool Entity1 { get; set; }         
     public bool Entity2 { get; set; }         
  }

  static void TransitionDetection(CloudTable tbl, CloudTable e1Tbl, CloudTable e2Tbl, LogEntry currentLogEntry)
  {
     if (currentLogEntry.Id> 1)
     {
        // Retrieve the previous log entry
        string pkFilter = TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, currentLogEntry.PartitionKey);
        string rkFilter = TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.Equal, (currentLogEntry.Id - 1).ToString());
        string combinedFilter = TableQuery.CombineFilters(pkFilter, TableOperators.And, rkFilter);
        TableQuery<LogEntry> query = new TableQuery<LogEntry>().Where(combinedFilter);
        LogEntry prevLogEntry = tbl.ExecuteQuery(query).ToList()[0];

        // If Entity1 transitioned, record it
        if (prevLogEntry.Entity1 != currentLogEntry.Entity1)
        {
           e1Tbl.Execute(TableOperation.Insert(currentLogEntry));
        }

        // If Entity2 transitioned, record it
        if (prevLogEntry.Entity2 != currentLogEntry.Entity2)
        {
           e2Tbl.Execute(TableOperation.Insert(currentLogEntry));
        }
     }
  }

  static void Main(string[] args)
  {
     string storageConnection = "DefaultEndpointsProtocol=https;AccountName=MyTable;AccountKey=MY_KEY";

     // Select table
     CloudStorageAccount storageAccount = CloudStorageAccount.Parse(storageConnection);
     CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
     CloudTable table = tableClient.GetTableReference("LogTable");
     CloudTable entity1TransitionTable = tableClient.GetTableReference("Entity1TransitionTable");
     CloudTable entity2TransitionTable = tableClient.GetTableReference("Entity2TransitionTable");
     table.CreateIfNotExists();
     entity1TransitionTable.CreateIfNotExists();
     entity2TransitionTable.CreateIfNotExists();

     // Add Log Entries
     int id = 0;

     LogEntry le1 = new LogEntry("0", ++id, "May 1 2015", true, false);
     TransitionDetection(table, entity1TransitionTable, entity2TransitionTable, le1);
     table.Execute(TableOperation.Insert(le1));

     LogEntry le2 = new LogEntry("0", ++id, "May 2 2015", false, true);
     TransitionDetection(table, entity1TransitionTable, entity2TransitionTable, le2);
     table.Execute(TableOperation.Insert(le2));

     LogEntry le3 = new LogEntry("0", ++id, "May 3 2015", false, false);
     TransitionDetection(table, entity1TransitionTable, entity2TransitionTable, le3);
     table.Execute(TableOperation.Insert(le3));

     LogEntry le4 = new LogEntry("0", ++id, "May 4 2015", true, false);
     TransitionDetection(table, entity1TransitionTable, entity2TransitionTable, le4);
     table.Execute(TableOperation.Insert(le4));

     LogEntry le5 = new LogEntry("0", ++id, "May 5 2015", false, true);
     TransitionDetection(table, entity1TransitionTable, entity2TransitionTable, le5);
     table.Execute(TableOperation.Insert(le5));

     LogEntry le6 = new LogEntry("0", ++id, "May 7 2015", true, false);
     TransitionDetection(table, entity1TransitionTable, entity2TransitionTable, le6);
     table.Execute(TableOperation.Insert(le6));

     Console.ReadKey();
  }

如果您使用 TableXplorer 之类的应用程序检查表格,您将观察到以下结果:

日志表

Entity1TransitionTable

Entity2TransitionTable

【讨论】:

    猜你喜欢
    • 2011-08-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-16
    相关资源
    最近更新 更多