Pregunta

Estoy tratando de hacer algo que se vea muy simple, pero alcancé dificultades masivas cuando quiero hacer que sea más dinámica.

    Expression<Func<TableServiceEntity, bool>> predicate = (e) => e.PartitionKey == "model" && (e.RowKey == "home" || e.RowKey == "shared");

context.CreateQuery<TableServiceEntity>(tableName).Where(predicate);

Me gustaría pasar una matriz de Rowkey en lugar de tener que tener un código duro el predicado.

Cuando intento construir un árbol de expresión, recibo una excepción no compatible, creo que no es compatible con la invocación como parte del árbol de expresión.

¿Alguien sabe cómo construir y expresar árboles exactamente como el predicado para evitar la excepción no compatible?

Gracias por adelantado

¿Fue útil?

Solución

Por lo tanto, puede construir la consulta dinámicamente usando algo como esto (tomado de Phluffyfotos muestra):

        Expression<Func<PhotoTagRow, bool>> search = null;
        foreach (var tag in tags)
        {
            var id = tag.Trim().ToLowerInvariant();

            if (String.IsNullOrEmpty(id))
            {
                continue;
            }

            Expression<Func<PhotoTagRow, bool>> addendum = t => t.PartitionKey == id;

            if (search == null)
            {
                search = addendum;
            }
            else
            {
                search = Expression.Lambda<Func<PhotoTagRow, bool>>(Expression.OrElse(search.Body, addendum.Body), search.Parameters);
            }
        }

Ahora, una vez que haya "buscado", puede pasarlo como el predicado en su cláusula WHERE.

Sin embargo, , quiero convencerte de que no hagas esto. Estoy respondiendo a su pregunta, pero le estoy diciendo que es una mala idea hacer un múltiplo '|' O cláusula en el almacenamiento de la tabla. La razón es que hoy al menos, estas consultas no pueden optimizarse y causan una exploración de mesa completa. El rendimiento será horrible con cualquier cantidad no trivial de datos. Además, si construye sus predicados dinámicamente como este, corre el riesgo de soplar el límite de la URL (tenga en cuenta).

Este código en Phluffyfotos muestra cómo, pero en realidad es una mala práctica (lo sé, lo escribí). Realmente debe optimizarse para ejecutar cada una o cláusula por separado en paralelo. Así es como realmente deberías hacerlo. Y las cláusulas están bien, pero o las cláusulas deben ser paralelizadas (use PLINQ o TPL) y debe agregar los resultados. Será mucho más rápido.

hth.

Otros consejos

Creo que HTH dijo sobre este tipo de consulta que realiza una tabla de mesa completa es incorrecta de la documentación que he leído.Azure realizará una exploración de particiones en lugar de un escaneo de tabla que es una gran diferencia en el rendimiento.

Aquí está mi solución, lea también la respuesta de HTH que señaló que esto no es una mejor práctica.

var parameter = Expression.Parameter(typeof(TableServiceEntity), "e");

var getPartitionKey = typeof(TableServiceEntity).GetProperty("PartitionKey").GetGetMethod();
var getRowKey = typeof(TableServiceEntity).GetProperty("RowKey").GetGetMethod();

var getPartition = Expression.Property(parameter, getPartitionKey);
var getRow = Expression.Property(parameter, getRowKey);

var constPartition = Expression.Constant("model", typeof(string));
var constRow1 = Expression.Constant("home", typeof(string));
var constRow2 = Expression.Constant("shared", typeof(string));

var equalPartition = Expression.Equal(getPartition, constPartition);
var equalRow1 = Expression.Equal(getRow, constRow1);
var equalRow2 = Expression.Equal(getRow, constRow2);

var and = Expression.AndAlso(equalPartition, Expression.OrElse(equalRow1, equalRow2));

return Expression.Lambda<Func<TableServiceEntity, bool>>(and, parameter);

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top