2011-02-07 25 views
8

Tengo una aplicación que utiliza algunos principios de almacenamiento de datos como el modelado dimensional para hacer informes en una base de datos bastante simple.Pregunta estadística en SQL: ¿esto es posible con NHibernate LINQ?

Un ejemplo (simplificado) entidad llamada Call ve así:

public virtual long Id { get; set; } 
    public virtual string OriginatorNumber { get; set; } 
    public virtual string DestinationNumber { get; set; } 
    public virtual DateDimension DateDimension { get; set; } 

Algunas de las propiedades del modelo real se han eliminado, ya que son irrelevantes. El DateDimension simplificado se ve así:

public virtual long Id { get; set; } 
    public virtual DateTime Date { get; set; } 
    public virtual int DayOfMonth { get; set; } 
    public virtual int Weekday { get; set; } 

hay muchos más columnas de este tipo - que se rellena previamente para la década actual configuración de la aplicación. Entonces, cada fecha en toda la década tiene una fila en esta tabla, y cada Llamada tiene un enlace a la fecha en que ocurrió. Todo esto está mapeado en Fluent NHibernate y funciona bien.

Si quiero hacer algunos informes, puedo hacerlo fácilmente con el proveedor mejorado NHibernate LINQ en 3.0. Nos gustaría usar LINQ para la mantenibilidad mejorada que nos brinda, pero si realmente DEBEMOS, consideraremos HQL, ICriteria o incluso SQL simple.

Supongamos que quiero crear un informe que muestre el número de llamadas de un cierto número, dividido por el día de la semana en que ocurren. Puedo hacer eso fácilmente de esta manera:

 var query = Calls 
      .Where(c => c.OriginatorNumber == "402") 
      .GroupBy(c => c.DateDimension.Weekday) 
      .Select(g => new { Day = g.Key, Calls = g.Count() }); 

En este ejemplo, "Llamadas" es básicamente una IQueryable regresó de proveedor de NHibernates LINQ (consulta) a través de una interfaz de repositorio. La consulta anterior me da los resultados correctos, NHibernate Profiler me muestra que el SQL es bastante óptimo, todo está bien.

Sin embargo, si quiero hacer algo un poco más avanzado, me quedo atascado. Digamos que quiero la cantidad promedio de llamadas por día de la semana. No muy lejos de lo de arriba, ¿verdad? Solo necesito averiguar el número de fechas únicas que tiene cada día de la semana en el conjunto de resultados, dividir el número total de llamadas por él y estamos listos, ¿no? Bueno, no, aquí es donde empiezo a golpear las limitaciones del proveedor NHibernate LINQ. Con LINQ a objetos que pude construir una consulta para hacerlo - algo en la línea de

.Select(g => g.Count()/g.GroupBy(c => c.DateDimension.Date).Count()); 

Sin embargo, esto no se convierte en la consulta correcta cuando se utiliza en NHibernate. Más bien, convierte ambas llamadas .Count() en el anterior en el mismo recuento (*) de registros de llamadas, por lo que el resultado es siempre 1.

PODRÍA, por supuesto, consultar para cada llamada, día de la semana y fecha como nuevo objeto anónimo, luego haga los cálculos en el lado de la aplicación, pero de acuerdo con la sabiduría convencional, That's Just Wrong (tm). Podría terminar haciéndolo en desesperación, aunque eso signifique dolor cuando la mesa crezca a un millón de llamadas ++.

La siguiente es una consulta SQL que me da el resultado que estoy buscando.

select ss.Weekday, AVG(cast(ss.Count as decimal)) 
from 
(
select dd.Weekday, dd.Date, COUNT(*) as Count 
from Call c 
left outer join DateDimension dd 
    on c.DateDimension_id = dd.Id 
where c.OriginatorNumber = '402' 
group by dd.Weekday, dd.Date 
) ss 
group by ss.Weekday 
order by ss.Weekday 

¿Es posible hacer esto con el proveedor NHibernate LINQ? O, si eso no es posible, ¿qué tan cerca puedo llegar antes de tener que dejar que la aplicación obtenga el resultado intermedio y haga el resto?

+0

Quizás va por el camino equivocado al respecto. ¿Qué le parece crear un esquema en estrella y completar medidas calculadas? – epitka

+0

Bueno, ese es un punto interesante, sin embargo, entiendo que cada entidad en la tabla de "hechos" (es decir, llamadas en mi ejemplo) tiene un FK en cada tabla de dimensiones relevante. ¿Cómo puedo crear un esquema en estrella que me ayude a determinar la fecha de las llamadas y señalarlo desde cada registro de llamadas? Pero, en general, estoy muy abierto a la posibilidad de que estoy haciendo esto de la manera incorrecta. :) –

Respuesta

1

Hay muchas cosas que no puede hacer con el proveedor de LINQ. Usar HQL o CreateCriteria es algo que tendrá que aceptar con NHibernate.

No lo he intentado, pero parece que debería poder hacer lo que quiera con HQL o CreateCriteria (con DetatchedCriteria).

Si está desesperado también puede recurrir a SQL simple utilizando CreateSqlQuery.

+1

Hola, y gracias por su respuesta. Sí, podría tener que recurrir a esto, el problema es básicamente que quería presentar a mis usuarios una API basada en IQueryable , para que pudieran filtrar con Where() antes de pasarme IQueryable para la agrupación. Hubiera sido muy elegante, supongo que lo que realmente debería hacer es convertirme en un gran codificador y contribuir a NHibernate. :) Gracias por la entrada, voy a ver las formas HQL e ICriteria de hacer las cosas. –