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