2013-05-12 62 views
4

有没有办法使NHibernate的这个查询更容易?如何使用“不在”做NHibernate QueryOver?

对于理解,这是我想与NHibernate创建查询:

Select * from Task 
Where task_id not in 
(Select task_id from UserTask 
Where solved = 1 AND [user_id] = 1) 

而这一次是我在C#代码与NHibernate

public IList<Task> RandomTasks(List<int> subject_ids, int userId) 
{ 
    //Gets all Ids where the User has solved the Task 
    List<int> task_ids = new List<int>(_session.Query<UserTask>() 
         .Where(x => x.User.user_id == userId) 
         .Where(x => x.solved) 
         .Select(x => x.Task.task_id)); 

    //Gets all Tasks except the task_ids from the result of the query befor 
    var query = _session.QueryOver<Task>() 
         .Where(s => s.Subject.subject_id.IsIn(subject_ids)) 
         .Where(t => !t.task_id.IsIn(task_ids)) 
         .Take(10) 
         .List(); 

    return query; 
} 

查询返回正确的结果但我认为可能有更简单的方法来获得相同的结果。

回答

1

如果您愿意INNER SELECT,NHiberante确实有适合您的解决方案。它被称为DetachedCriteria。 (尝试检查here类似的例子)

所以,首先我们将创建一个内部的选择:

var sub = DetachedCriteria 
    .For<UserTask>() 
    // WHERE 
    .Add(Restrictions.In("UserId", new int[] { 1, 2 })) // example of filtering 'user_id' 
    .Add(Restrictions.Eq("solved", true))    // 'solved' 
    .SetProjection(Projections.Property("TaskId")); // TaskId the SELECT clause 

(我不知道你的型号和命名,如TASK_ID VS 任务id ...但意图应该清楚)

随着DetachedCritera我们可以做很多事情,我们可以加入其他引用的对象/表格,过滤它们...与标准的QueryOver一样。唯一的区别是,我们应该返回投影(SELECT taskid的)被用作在另一个查询的过滤器:

var criteria = session.CreateCriteria<Task>(); 
criteria 
    . Where(...        // your filters applied on Task 
    .Add(Subqueries.PropertyIn("ID", sub)); // Task.ID in (select... 

变种结果= criteria.List();

注意。该解决方案不仅可以工作;),但大多数情况下,它已准备好用于 寻呼排序。因此,即使在情况下,即内部的选择将返回更多的“相似”的结果(同IDS),上选择将返回各自的任务只有一次......

欲了解更多信息:15.8. Detached queries and subqueries

0

您可以使用left join

Select t.* from Task t 
left join UserTask ut on t.Id = ut.TaskId 
    and ut.UserId = 1 and ut.solved = 1 
where ut.id is null 
+0

谢谢您回答。但是,我需要的是使用nHibernate的不同解决方案。或者是否有可能做到与nHibernate左连接? – 2013-05-12 21:18:44