c# - columns - Dynamic Linq+Entity Framework: modificaciones de fecha y hora para la selección dinámica
select all entity framework c# (1)
Estoy tratando de encontrar una manera de mover la hora UTC a Local antes de hacer una agrupación sql. Estoy usando System.Linq.Dynamic (administrado aquí https://github.com/kahanu/System.Linq.Dynamic ). Funciona muy bien para hacer selecciones dinámicas sin tener en tiempo de compilación los campos requeridos. En nuestro caso, almacenamos todas las fechas en UTC. En esta selección dinámica, es posible que alguien desee hacer un groupby en la Hora, año, mes, etc. Tenemos que mover los datos a una hora local en este caso, para evitar confusiones.
Ejemplo:
var select = queryable.Select(string.Format("new ({0}, {1})", datetimeColumn, someOtherColumn));
Normalmente en nuestro tsql o incluso en el marco de la entidad utilizando expresiones lambda, puede agregar su desplazamiento deseado. Pero en la opción dynamic linq, parece que no puede realizar ninguna operación de fecha como DateTime.AddHours (x) o DateTime.Subtract (x) como lo haría con Linq2Sql. Entity Framework 6 quiere que uses DbFunctions.AddHours (x) , etc. Sin embargo, el código dinámico de linq, sin modificaciones, no aceptará las funciones de Db sin error.
Ejemplo:
var select = queryable.Select(string.Format("new (System.Data.Entity.DbFunctions.AddHours({0},7) as {0}, {1})", datetimeColumn, someOtherColumn));
Devuelve un error: No existe propiedad o campo ''Sistema'' en el tipo XXX
(eliminar el espacio de nombres no ayuda).
Usando el código deseado:
var select = queryable.Select(string.Format("new ({0}.AddHours(7), {1})", datetimeColumn, someOtherColumn));
Resultados con error: LINQ to Entities no reconoce el método ''System.DateTime AddHours (Double)'', y este método no se puede traducir a una expresión de tienda.
Quiero que SQL realice la matemática de fecha y hora antes del groupby. Una vez que se produce el groupby, ya no existe el concepto de UTC ya que el usuario verá el conjunto de resultados localizado.
Me temo que voy a actualizar mi fork github con algunas extensiones para admitir la aprobación de las extensiones de framework de entidad, pero antes de hacerlo, quería ver si alguien más tenía una solución o una idea.
Nota: No estoy usando DateTimeOffset debido a las posibilidades de cambiar las tecnologías del almacén de datos SQL.
Puede publicar el proceso de la expresión de consulta con ExpressionVisitor
personalizado y reemplazar los métodos no compatibles con sus equivalentes de DbFunctions
.
Aquí hay un punto de partida para obtener la idea:
public static class QueryableExtensions
{
public static IQueryable BindDbFunctions(this IQueryable source)
{
var expression = new DbFunctionsBinder().Visit(source.Expression);
if (expression == source.Expression) return source;
return source.Provider.CreateQuery(expression);
}
class DbFunctionsBinder : ExpressionVisitor
{
protected override Expression VisitMethodCall(MethodCallExpression node)
{
if (node.Object != null && node.Object.Type == typeof(DateTime))
{
if (node.Method.Name == "AddHours")
{
var timeValue = Visit(node.Object);
var addValue = Visit(node.Arguments.Single());
if (timeValue.Type != typeof(DateTime?)) timeValue = Expression.Convert(timeValue, typeof(DateTime?));
if (addValue.Type != typeof(int?)) addValue = Expression.Convert(addValue, typeof(int?));
var methodCall = Expression.Call(
typeof(DbFunctions), "AddHours", Type.EmptyTypes,
timeValue, addValue);
return Expression.Convert(methodCall, typeof(DateTime));
}
}
return base.VisitMethodCall(node);
}
}
}
y uso de muestra:
var select = queryable
.Select(string.Format("new ({0}.AddHours(7), {1})", datetimeColumn, someOtherColumn))
.BindDbFunctions();