2011-03-21 92 views
6

背景,使用FluentNHibernate,最新開發版本與NHibernate 3.0一起工作。NHibernate流利(QueryOver)替代HQL與相關子查詢

這裏是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"); 
    } 
} 

映射工作正常,我可以做的查詢,如沒有問題如下:

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

這給了我所有的工作項目(基本上是幫助臺故障單)在當前日期由特定用戶觸及。

不過,我一直有麻煩翻譯下面的HQL成流利聲明:

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)) 

這個查詢給了我一個工人被放置在一個封閉的狀態,所有的工作項目列表。鑑於門票存儲在數據庫中的方式(每張門票都有多條記錄(每次更新一條記錄),並且主管人員經常會在工人關閉門票後向票據添加備註,導致出現這種情況,我不能只看一個封閉的狀態最後一個版本號來可靠地告訴我是誰收的門票。

任何幫助將不勝感激,因爲我寧願從HQL和魔法串儘可能移開。

回答

0

我想這個應該是訣竅,最難的部分是真正處理你在那裏得到的數學運算,你必須進入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(); 

在我的測試中,這產生了以下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)]