4

我需要从一个列表中识别出另一个列表中不存在的项目。这两个列表属于不同的实体 (ToDoWorkshopItem)。Name如果在任何待办事项列表项目中匹配,我认为研讨会项目在待办事项列表中。

以下是我所追求的,但每次我重新访问它时都会感到尴尬和难以理解。我使用 NHibernateQueryOver语法来获取两个列表,然后使用 LINQ 语句过滤到仅满足要求的 Workshop 项目(DateDue在接下来的两周内,并且Name不在 ToDo 项目列表中。

var allTodos = Session.QueryOver<ToDo>().List();
var twoWeeksTime = DateTime.Now.AddDays(14);
var workshopItemsDueSoon = Session.QueryOver<WorkshopItem>()
                                  .Where(w => w.DateDue <= twoWeeksTime).List();

var matches = from wsi in workshopItemsDueSoon
              where !(from todo in allTodos
                      select todo.TaskName)
                    .Contains(wsi.Name)
              select wsi;

理想情况下,我希望只有一个 NHibernate 查询返回WorkshopItem符合我要求的 s 列表。

4

3 回答 3

2

我已经设法整理了@CSL 提出的答案的 Linq 版本,并将其标记为已接受的答案,因为它使我朝着以下方向发展。

var twoWeeksTime = DateTime.Now.AddDays(14);
var subquery = NHibernate.Criterion.QueryOver.Of<ToDo>().Select(t => t.TaskName);
var matchingItems = Session.QueryOver<WorkshopItem>()
                           .Where(w => w.DateDue <= twoWeeksTime && 
                                       w.IsWorkshopItemInProgress == true)
                           .WithSubquery.WhereProperty(x => x.Name).NotIn(subquery)
                           .Future<WorkshopItem>();

它返回我期望的结果并且不依赖于魔术字符串。我很犹豫,因为我不完全理解 WithSubquery(以及内联它是否会是一件好事)。似乎等于

WHERE WorkshopItem.Name IS NOT IN (subquery)

我也不明白Future代替List。如果有人能对那些会有所帮助的人有所了解。

于 2013-06-05T20:57:15.753 回答
1

我不是 100% 确定如何使用 LINQ 来实现你所需要的,所以为了给你一个选择,我只是提出了一个使用 nHibernate Criteria 的替代解决方案(这将在一次数据库命中中执行):

// Create a query
ICriteria query = Session.CreateCriteria<WorkShopItem>("wsi");

// Restrict to items due within the next 14 days
query.Add(Restrictions.Le("DateDue", DateTime.Now.AddDays(14));

// Return all TaskNames from Todo's
DetachedCriteria allTodos = DetachedCriteria.For(typeof(Todo)).SetProjection(Projections.Property("TaskName"));

// Filter Work Shop Items for any that do not have a To-do item 
query.Add(SubQueries.PropertyNotIn("Name", allTodos);

// Return results
var matchingItems = query.Future<WorkShopItem>().ToList()
于 2013-06-05T14:50:20.640 回答
1

我会推荐

var workshopItemsDueSoon = Session.QueryOver<WorkshopItem>()
                                  .Where(w => w.DateDue <= twoWeeksTime)
var allTodos = Session.QueryOver<ToDo>();

代替

var allTodos = Session.QueryOver<ToDo>().List();
var workshopItemsDueSoon = Session.QueryOver<WorkshopItem>()
                                  .Where(w => w.DateDue <= twoWeeksTime).List();

这样在您需要之前不会对集合进行迭代。

我发现使用 linq 扩展方法使子查询更具可读性和不那么尴尬是很有帮助的。

例如:

var matches = from wsi in workshopItemsDueSoon
              where !allTodos.Select(it=>it.TaskName).Contains(wsi.Name)
              select wsi

就个人而言,由于查询相当简单,我更愿意这样做:

var matches = workshopItemsDueSoon.Where(wsi => !allTodos.Select(it => it.TaskName).Contains(wsi.Name))

后者对我来说似乎不那么冗长。

于 2013-06-05T15:00:49.857 回答