Hay algunas maneras de hacer esto y cómo lo hace depende un poco de su preferencia personal así como también metas de rendimiento potencial.
- Cree una clase amalgamada que represente todos los tipos consultados. Si tuviera StatusUpdateEntry y un NotificationEntry, simplemente fusionaría cada propiedad en una sola clase. El serializador será automáticamente completará las propiedades correctas y dejará las demás nulas (o predeterminadas). Si también coloca una propiedad 'tipo' en la entidad (calculada o configurada en almacenamiento), podría fácilmente activar ese tipo. Como siempre recomiendo mapear desde entidad de tabla a su propio tipo en la aplicación, esto también funciona bien (la clase solo se usa para DTO).
Ejemplo:
[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";
}
}
}
- omitir el proceso de serialización. Puede hacerlo usted mismo enganchando el evento ReadingEntity. Le da el XML sin procesar y puede elegir serializar como quiera. Jai Haridas y Pablo Castro dieron un código de ejemplo para leer una entidad cuando no se conoce el tipo (incluido a continuación), y se puede adaptar para leer tipos específicos que usted conoce.
La desventaja de ambos enfoques es que en algunos casos termina extrayendo más datos de los que necesita. Debe ponderar cuánto desea realmente consultar un tipo frente a otro. Tenga en cuenta que puede usar la proyección ahora en el almacenamiento de la Tabla, por lo que también reduce el tamaño del formato del cable y puede acelerar realmente las cosas cuando tiene entidades más grandes o muchas más para regresar. Si alguna vez tuvo la necesidad de consultar solo un tipo, probablemente usaría RowKey o PartitionKey para especificar el tipo, lo que me permitiría consultar solo un tipo a la vez (podría usar una propiedad, pero eso no es tan eficiente para fines de consulta como PK o RK).
Editar: Como señaló Lucifure, otra gran opción es diseñar a su alrededor. Utiliza múltiples tablas, consultas en paralelo, etc. Necesitas intercambiar eso con la complejidad de los tiempos de espera y el manejo de errores, por supuesto, pero también es una opción viable y, a menudo, buena dependiendo de tus necesidades.
la lectura de un Entidad genérico:
[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);
}
}
Espero que la gente se de cuenta de que esta es una respuesta muy antigua ahora. Las entidades genéricas o dinámicas se admiten directamente en el SDK de almacenamiento. – dunnry