2011-03-21 8 views
6

Antecedentes, utilizando FluentNHibernate, la última versión de desarrollo de desarrollo que funciona con NHibernate 3.0.Reemplazo fluido de NHibernate (QueryOver) para HQL con subconsulta correlacionada

Aquí está la declaración de tipos de WorkIncident:

// Enumeration used in class below. 
public enum TicketStatus 
{ 
    Open = 1, 
    Closed = 10, 
    Hold = 20 
} 

// Ticket class. 
public class WorkIncident 
{ 
    public virtual int EntryId { get; set; } 
    public virtual int TicketNumber { get; set; } 
    public virtual string ModifierNtId { get; set; } 
    public virtual DateTime ModifiedDate { get; set; } 
    public virtual TicketStatus Status { get; set; } 
    public virtual int Version { get; set; } 
    public virtual string Title { get; set; } 
    public virtual string Details { get; set; } 
} 

// FluentNHibernate mapping 
public class WorkIncidentMap : ClassMap<WorkIncident> 
{ 
    public WorkIncidentMap() 
    { 
     Table("incident_details"); 
     Id(wi => wi.EntryId, "wiid"); 
     Map(wi => wi.TicketNumber, "workitem_number"); 
     Map(wi => wi.Title, "workitem_title"); 
     Map(wi => wi.Details, "workitem_comment"); 
     Map(wi => wi.ModifiedDate, "workitem_modified_on"); 
     Map(wi => wi.ModifierNtId, "modified_by_worker_nt_id"); 
     Map(wi => wi.Status, "workitem_status_lookup_id").CustomType<EnumType<Status>>(); 
     Map(wi => wi.Version, "workitem_version"); 
    } 
} 

El mapeo funciona bien, y puedo hacer consultas como la siguiente sin ningún problema:

session.QueryOver<AltirisIncident>() 
    .Where(ai => ai.ModifierNtId == worker.Name.Replace("\\", @"\")) 
    .AndRestrictionOn(ai => ai.ModifiedDate) 
    .IsBetween(DateTime.Today) 
    .And(DateTime.Today.AddDays(1)) 
    .List<WorkIncident>(); 

Esto me da todo el trabajo artículos (básicamente tickets de problemas de la mesa de ayuda) tocados por un usuario específico en la fecha actual.

Sin embargo, he estado teniendo problemas para traducir la siguiente HQL en una declaración de fluidez:

from WorkIncident as t1 
where t1.ModifierNtId = :ntid 
and  t1.ModifiedDate between :startdate and :enddate 
and  t1.Status = :status 
and  (t1.Version = 1 
or  t1.TicketNumber in (
    select t2.TicketNumber 
    from  WorkIncident as t2 
    where  t2.Status != t1.Status 
    and  t2.TicketNumber = t1.TicketNumber 
    and  t2.Version = t1.Version - 1)) 

Esta consulta me da la lista de todos los elementos de trabajo que se colocaron en un estado cerrado por un trabajador. Dada la forma en que se almacenan los boletos en la base de datos (cada ticket tiene múltiples registros (uno para cada actualización) y los supervisores a menudo agregarán notas a un ticket después de que un trabajador lo haya cerrado, esto genera situaciones en las que no puedo mirar el último número de versión con un estado cerrado a dime fiable que cerró un boleto.

Cualquier ayuda sería muy apreciada, como yo preferiría a alejarse de HQL y mágicas cuerdas tanto como sea posible.

Respuesta

0

pienso esto debería ser el truco. La parte difícil es realmente manejar esa operación matemática que tienes allí. Tienes que entrar en proyecciones SQLFunction

session.QueryOver<WorkIncident>(() => t1Alias) 
       .Where(w => w.ModifierNtId == "test") 
       .And(w => w.ModifiedDate < DateTime.Now && w.ModifiedDate > DateTime.Now) 
       .And(w => w.Status == TicketStatus.Open) 
       .And(Restrictions.Disjunction() 
        .Add(Restrictions.Where<WorkIncident>(w => w.TicketNumber == 1)) 
        .Add(Subqueries.WhereProperty(() => t1Alias.TicketNumber).In(
         QueryOver.Of<WorkIncident>(() => t2Alias) 
           .Where(() => t2Alias.Status != t1Alias.Status) 
           .And(() => t2Alias.TicketNumber == t1Alias.TicketNumber) 
           .And(Restrictions.EqProperty(
            Projections.Property<WorkIncident>(w=> w.Version), 
            Projections.SqlFunction(
             new VarArgsSQLFunction("(","-",")"), 
             NHibernateUtil.Int32, 
             Projections.Property(()=> t1Alias.Version), 
             Projections.Constant(1) 
            ))) 
           .Select(w => w.TicketNumber))) 
       ).List(); 

En mi prueba, esto generó el siguiente SQL

SELECT <snip...> 
FROM incident_details this_ 
WHERE this_.modified_by_worker_nt_id = @p0 
    and (this_.workitem_modified_on < @p1 and this_.workitem_modified_on > @p2) 
    and this_.workitem_status_lookup_id = @p3 
    and (this_.workitem_number = @p4 
    or this_.workitem_number in 
     (SELECT this_0_.workitem_number as y0_ 
     FROM incident_details this_0_ 
     WHERE not (this_0_.workitem_status_lookup_id = this_.workitem_status_lookup_id) 
     and this_0_.workitem_number = this_.workitem_number 
     and this_0_.workitem_version = ([email protected]))); 
     @p0 = 'test' [Type: String (0)], @p1 = 10/26/2012 11:26:24 PM [Type: DateTime (0)], @p2 = 10/26/2012 11:26:24 PM [Type: DateTime (0)], @p3 = 1 [Type: Int32 (0)], @p4 = 1 [Type: Int32 (0)], @p5 = 1 [Type: Int32 (0)] 
Cuestiones relacionadas