Azure表存储反向关系

时间:2013-02-09 23:39:14

标签: azure azure-storage azure-table-storage

我正在使用azure表存储(注意: Azure SQL),我有以下情况:

在我的应用程序中,我有许多“邀请”用户的组织,并且在邀请中存在关联的“角色”和“过期”。一旦组织邀请了一个用户,我希望组织看到他们邀请的用户列表,我希望用户看到他们被邀请参加的组织列表。

我认为在我的应用程序和这种情况下,数字会很少(即组织只会邀请一些用户,而用户通常只会被一个组织邀请)。然而,即使数量非常大,人们还是会采用一般模式来处理这种情况吗?

1 个答案:

答案 0 :(得分:4)

我目前使用三种方法,具体取决于我的需求:

<强>事务

我将正向和反向关系存储在同一个分区上...这意味着每个实体都在同一个分区上(即此方法受单个分区限制),但这意味着您可以使用批处理事务同时插入正向和反向关系,这意味着您知道它们将始终是正确的。

public class OrganisationInvite : TableEntity
{
    // Partition Id - string.Empty
    // Row Id - "Invite_" + OrangisationId + "_" + UserId

    public string Role { get; set; }
    public DateTime Expiry { get; set; }
}

public class OrganisationRequest : TableEntity
{
    // Partition Id - string.Empty
    // Row Id - "Request_" + UserId + "_" + OrganisationId

    public string Role { get; set; }
    public DateTime Expiry { get; set; }
}

要查询我使用t.RowKey.StartsWith("Request_...")t.RowKey.StartsWith("Invite_..."),具体取决于我是否要获取用户/组织邀请列表。

我想这最适合在数据非常关键时使用。

最终一致性

我为两个表提供了所有属性,但它们位于不同的分区上,这为您提供了极好的可伸缩性,但是您放弃了事务。我使用消息队列来更新反向关系以匹配正向关系,因此最终数据将匹配。 (但有一段时间它可能不会)。

// Assume both in the same table, thus the prefix on partition
public class OrganisationInvite : TableEntity
{
    // Partition Id - "Invite_" + OrangisationId
    // Row Id -  UserId

    public string Role { get; set; }
    public DateTime Expiry { get; set; }
}

public class OrganisationRequest : TableEntity
{
    // Partition Id - "Request_" + UserId
    // Row Id - OrganisationId

    public string Role { get; set; }
    public DateTime Expiry { get; set; }
}

要查询我使用t.PatitionKey == "Request_..."t.PatitionKey == "Invite_...",具体取决于我是否要获取用户/组织邀请列表。也许您会将其中一个视为“真相来源”,因此当用户接受邀请时,您会查找“真相来源”并向用户提供该角色等。

这是最具扩展性的解决方案,如果您在其上使用缓存,尤其有意义。

真相来源

在这种情况下,我只在一个实体上给出属性,而在另一个实体上只有反向关系的键。您可以将实体添加到最长或最查询的列表中......在这种情况下,我会说它是组织的邀请。与最终一致性方法一样,您将对反向关系进行排队以添加反向实体。除了添加新关系时(因为在创建反向关系之前有一段时间),此方法为您提供了完整的数据一致性,并且具有高度可伸缩性 - 但读取反向列表的成本更高。

 // Assume both in the same table, thus the prefix on partition
public class OrganisationInvite : TableEntity
{
    // Partition Id - "Invite_" + OrangisationId
    // Row Id -  UserId

    public string Role { get; set; }
    public DateTime Expiry { get; set; }
}

public class OrganisationRequest : TableEntity
{
    // Partition Id - "Request_" + UserId
    // Row Id - OrganisationId
}

您可以使用t.PatitionKey == "Invite_..."轻松查询转发关系。然而,反向关系并非微不足道。您必须使用t.PatitionKey == "Request_..."进行查询并创建n个并行调用以获取每个项目的数据转发数据(在这种情况下,使用在反向关系的RowKey中找到的org id)。如果该项目不存在,则不将其添加到最终列表中。这可确保如果组织更改其角色,例如,用户将在下次命中时看到此更改。

我认为如果很少使用反向关系,并且数据是最新的(我正在考虑用户权限等等),这个方法很有用。