如何使用单个查询到Azure的表存储检索多个类型的实体?(How do I retrieve mul

2019-07-29 11:34发布

我试图抓住表如何Azure存储工作为了创建Facebook风格的饲料和我卡在如何检索条目。

(我的问题是几乎相同https://stackoverflow.com/questions/6843689/retrieve-multiple-type-of-entities-from-azure-table-storage但答案的链接被打破了。)

这是我预期的方法:

  1. 创建我的应用程序中的所有用户都可以包含不同类型的项(通知,状态更新等),个人饲料。 我的想法是将它们存储在由每个用户的分区键进行分组的Azure Table中。

  2. 检索同一分区键中的所有条目,并把它传递给取决于条目类型不同的看法。

如何查询所有类型相同的基本类型,同时保持其独特的属性表存储?

CloudTableQuery<TElement>需要一个类型化的实体,如果我指定EntryBase作为一般的说法我没有得到具体的入门性质( NotificationSpecificPropertyStatusUpdateSpecificProperty ),反之亦然。

我的实体:

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; }
}

我对饲料查询:

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

    }

}

Answer 1:

最后还有一个官方的方法! :)

看的NoSQL样品这正是这一点从Azure存储团队博客链接:

Windows Azure的存储客户端库2.0表深潜



Answer 2:

有几种方法去这个怎么你做的这取决于你的个人喜好了一下,以及潜在的性能目标。

  • 创建一个代表所有查询类型的混汞类。 如果我有StatusUpdateEntry和NotificationEntry,那我就干脆每个属性合并为一个类。 串行器会自动填入正确的属性,离开他人空(或默认)。 如果你也把一个“类型”属性的实体(计算或存储设置),你可以很容易地在该类型切换。 因为我总是建议从表实体映射到自己的类型的应用程序,这正常工作,以及(类只成为用于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,你可以选择序列不过你想要的。 洁Haridas和Pablo卡斯特罗给了一些示例代码,阅读时你不知道的类型(包括下面)的实体,并且可以适应的是读取特定类型的,你知道的。

缺点这两种方法是,你最终会拉动更多的数据比你在某些情况下需要。 你需要权衡这对你真的是多么想查询一个类型与另一个。 请记住,您可以在表存储现在使用的投影,这样也降低了传输格式大小,才能真正加快速度,当你有更大的实体或许多返回。 如果你曾经需要查询只有一个类型,我可能会使用RowKey或PartitionKey的一部分指定类型,那么这将让我在一个时间查询只有一个类型(你可以使用一个属性,但这不是查询目的,PK或RK)为有效。

编辑:正如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);   
        }   
    }


Answer 3:

另一种选择,当然,是仅具有每表中的单个实体型,查询在平行的表和通过合并排序时间戳的结果。 从长远来看,这可能被证明是比较稳妥的选择参照的可扩展性和可维护性。

或者你需要使用通用实体一番风味的“dunnry”,其中非普通数据没有显式类型,并通过字典,而不是持续的概述。

我已经写了一个备用Azure的表存储客户端,Lucifure藏匿,其在蔚蓝的表存储包括从字典到持续/支持额外的抽象,并在您的情况可能会工作,如果这是你要追求的方向。

Lucifure藏匿支持大数据列> 64K,数组和清单,枚举,组合键,开箱系列化的,用户定义的变形,公共和私人属性和字段等等。 它可以免费供个人使用的http://www.lucifure.com或通过NuGet.com。

编辑:现在,开源在CodePlex上



Answer 4:

使用DynamicTableEntity如在查询的实体类型。 它可以查找属性的字典。 它可以返回任何实体类型。



文章来源: How do I retrieve multiple types of entities using a single query to Azure Table Storage?