2011-03-21 56 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)]