NHibernate Fluent (QueryOver) 使用相关子查询替换 HQL
背景,使用 FluentNHibernate,最新的开发版本与 NHibernate 3.0 一起使用。
以下是 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 和魔术字符串。
Background, using FluentNHibernate, lastest dev build working with NHibernate 3.0.
Here is the type declarations for 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");
}
}
The mapping works fine, and I can do queries like the following with no problems:
session.QueryOver<AltirisIncident>()
.Where(ai => ai.ModifierNtId == worker.Name.Replace("\\", @"\"))
.AndRestrictionOn(ai => ai.ModifiedDate)
.IsBetween(DateTime.Today)
.And(DateTime.Today.AddDays(1))
.List<WorkIncident>();
This gives me all of the work items (basically help desk trouble tickets) touched by a specific user on the current date.
However, I have been having trouble translating the following HQL into a fluent declaration:
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))
This query gives me the list of all work items that were placed in a closed status by a worker. Given the way the tickets are stored in the database (each ticket has multiple records (one for each update) and supervisors will often add notes to a ticket after a worker has closed it, leads to situations where I can't just look at the last version number with a closed status to reliably tell me who closed a ticket.
Any help would be greatly appreciated, as I would prefer to move away from HQL and magic strings as much as possible.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我认为这应该可以解决问题。困难的部分实际上是处理那里的数学运算。你必须进入 SQLFunction 投影
在我的测试中,这生成了以下 SQL
I think this should do the trick. The tough part is really handling that mathematical operation you've got there. You have to get into SQLFunction projections
In my test, this generated the following SQL