简体   繁体   English

如何使用“不在”的NHibernate QueryOver?

[英]How to do an NHibernate QueryOver with “not in”?

Is there a way to make this query easier with NHibernate? NHibernate有没有办法让这个查询更容易?

For the understanding, this is the query which I want to create with NHibernate: 为了理解,这是我想用NHibernate创建的查询:

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

And this one is my Code in C# with NHibernate 这个是我在NH#中的C#代码

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;
}

The query returns the correct result but I think there is maybe an easier way to get the same result. 查询返回正确的结果,但我认为可能有一种更简单的方法来获得相同的结果。

If you would prefer INNER SELECT , NHiberante does have the solution for you. 如果您更喜欢INNER SELECT ,NHiberante确实为您提供了解决方案。 It is called DetachedCriteria . 它被称为DetachedCriteria (try to check here for similar example) (试着在这里查看类似的例子)

So firstly we will create the inner select: 首先我们将创建内部选择:

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

(I am not sure about your model and naming eg task_id vs TaskId ... but the intention should be clear) (我不确定你的模型和命名,例如task_id vs TaskId ......但意图应该清楚)

With DetachedCritera we can do a lot, we can join other referenced objects/tables, filter them... as with standard QueryOver. 使用DetachedCritera我们可以做很多事情,我们可以加入其他引用的对象/表,过滤它们......就像标准的QueryOver一样。 The only difference is, that we should return Projection (SELECT TaskId) to be used as a filter in another query: 唯一的区别是,我们应该返回Projection(SELECT TaskId)作为另一个查询中的过滤器:

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

var result = criteria.List(); var result = criteria.List();

NOTE. 注意。 This solution will not only work ;), but mostly, it is ready for paging and sorting . 这个解决方案不仅可以工作;),但大多数情况下,它已准备好进行分页排序 So even in cases, that the inner select will return more 'similar' results (same ids), the upper select will return each task only once... 因此,即使在情况下,内部选择将返回更多“相似”结果(相同的ID),上部选择将仅返回每个任务一次...

For more information: 15.8. 有关更多信息: 15.8。 Detached queries and subqueries 分离的查询和子查询

You can use a left join : 您可以使用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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM