2012-05-22 30 views
5

Tôi đang cố gắng nắm bắt cách lưu trữ bảng Azure hoạt động để tạo nguồn cấp dữ liệu kiểu facebook và tôi bị kẹt về cách truy xuất các mục nhập.Tôi làm cách nào để truy xuất nhiều loại thực thể bằng cách sử dụng một truy vấn duy nhất để lưu trữ bảng Azure?

(Câu hỏi của tôi là gần như giống nhau như https://stackoverflow.com/questions/6843689/retrieve-multiple-type-of-entities-from-azure-table-storage nhưng liên kết trong câu trả lời là bị hỏng.)

Đây là cách tiếp cận dự định của tôi:

  1. Tạo một thức ăn cá nhân cho tất cả người dùng trong vòng ứng dụng của tôi có thể chứa các loại mục khác nhau (thông báo, cập nhật trạng thái, v.v.). Ý tưởng của tôi là lưu trữ chúng trong một bảng Azure được nhóm theo một khóa phân vùng cho mỗi người dùng.

  2. Truy xuất tất cả các mục nhập trong cùng một khóa phân vùng và chuyển nó đến các chế độ xem khác nhau tùy thuộc vào loại mục nhập.

Làm thế nào để truy vấn lưu trữ bảng cho tất cả các loại cùng loại cơ sở trong khi vẫn giữ đặc tính độc đáo của họ?

Các CloudTableQuery<TElement> đòi hỏi một tổ chức đánh máy, nếu tôi chỉ định EntryBase như là đối số generic Tôi không nhận được các thuộc tính nhập cảnh cụ thể (NotificationSpecificProperty, StatusUpdateSpecificProperty) và ngược lại.

thực thể của tôi:

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

truy vấn của tôi cho thức ăn chăn nuôi:

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 

    } 

} 

Trả lời

2

Có một vài cách để đi về vấn đề này và làm thế nào bạn làm điều đó phụ thuộc một chút về bạn sở thích cá nhân cũng như các mục tiêu hiệu suất tiềm năng.

  • Tạo một lớp hỗn hợp đại diện cho tất cả các loại được truy vấn. Nếu tôi có StatusUpdateEntry và một NotificationEntry, thì tôi sẽ đơn giản hợp nhất mỗi thuộc tính vào một lớp duy nhất. Bộ nối tiếp sẽ tự động điền vào các thuộc tính chính xác và để trống các thuộc tính khác (hoặc mặc định). Nếu bạn cũng đặt thuộc tính 'type' trên thực thể (được tính hoặc đặt trong bộ nhớ), bạn có thể dễ dàng bật loại đó. Vì tôi luôn khuyên bạn nên ánh xạ từ thực thể bảng sang loại của riêng bạn trong ứng dụng, điều này cũng hoạt động tốt (lớp chỉ được sử dụng cho DTO).

Ví dụ:

[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"; 
     } 
    } 
} 
  • Override quá trình tuần tự. Bạn có thể tự làm điều này bằng cách gắn kết sự kiện ReadingEntity. Nó cung cấp cho bạn XML thô và bạn có thể chọn serialize theo bất kỳ cách nào bạn muốn. Jai Haridas và Pablo Castro đã đưa ra một số mã ví dụ để đọc một thực thể khi bạn không biết loại (bao gồm bên dưới), và bạn có thể điều chỉnh nó để đọc các loại cụ thể mà bạn biết.

Nhược điểm của cả hai phương pháp là bạn sẽ kết thúc việc lấy nhiều dữ liệu hơn mức bạn cần trong một số trường hợp. Bạn cần phải cân nhắc điều này về số tiền bạn thực sự muốn truy vấn một loại so với loại khác. Hãy nhớ rằng bạn có thể sử dụng phép chiếu ngay bây giờ trong bộ nhớ Bảng, do đó cũng làm giảm kích thước định dạng dây và thực sự có thể tăng tốc độ khi bạn có các thực thể lớn hơn hoặc nhiều thứ để trả lại. Nếu bạn có nhu cầu truy vấn chỉ một kiểu duy nhất, tôi có thể sử dụng một phần của RowKey hoặc PartitionKey để chỉ định kiểu, sau đó cho phép tôi truy vấn chỉ một kiểu duy nhất tại một thời điểm (bạn có thể sử dụng một thuộc tính, nhưng đó không phải là hiệu quả cho các mục đích truy vấn như PK hoặc RK).

Chỉnh sửa: Như được ghi chú bởi Lucifure, một lựa chọn tuyệt vời khác là thiết kế xung quanh nó. Sử dụng nhiều bảng, truy vấn song song, vv Bạn cần phải giao dịch với sự phức tạp xung quanh thời gian chờ và xử lý lỗi tất nhiên, nhưng nó là một lựa chọn khả thi và thường xuyên tốt tùy thuộc vào nhu cầu của bạn.

Đọc một Generic Entity:

[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

Tôi hy vọng mọi người nhận ra đây là câu trả lời rất cũ. Các thực thể chung hoặc động được hỗ trợ trực tiếp trong SDK lưu trữ. – dunnry

1

Một lựa chọn khác, tất nhiên, là để chỉ có một loại thực thể duy nhất cho mỗi bảng, truy vấn bảng song song và hợp nhất các kết quả được sắp xếp theo dấu thời gian. Về lâu dài, điều này có thể chứng minh là sự lựa chọn thận trọng hơn với tham chiếu đến khả năng mở rộng và khả năng bảo trì. Ngoài ra, bạn sẽ cần phải sử dụng một số hương vị của các thực thể chung chung như được vạch ra bởi ‘dunnry’, nơi dữ liệu không phổ biến không được đánh máy một cách rõ ràng và thay vào đó vẫn tồn tại thông qua một từ điển.

Tôi đã viết một khách hàng lưu trữ bảng Azure thay thế, Lucifure Stash, hỗ trợ thêm abstractions trên bảng lưu trữ bảng xanh, bao gồm bền bỉ đến/từ từ điển và có thể hoạt động trong trường hợp của bạn. .

Lucifure Stash hỗ trợ cột dữ liệu lớn> 64K, mảng & danh sách, liệt kê, tổng hợp, ra khỏi hộp serialization, người dùng định nghĩa morphing, tài sản công cộng và tư nhân và các lĩnh vực và nhiều hơn nữa. Nó có sẵn miễn phí cho sử dụng cá nhân tại http://www.lucifure.com hoặc thông qua NuGet.com.

Chỉnh sửa: Bây giờ mở nguồn tại CodePlex

1

Sử dụng DynamicTableEntity như các loại thực thể trong các truy vấn của bạn. Nó có một từ điển các thuộc tính mà bạn có thể tra cứu. Nó có thể trả về bất kỳ loại thực thể nào.

Các vấn đề liên quan