识别一个列表中的项目,而不是另一个不同类型的列表中的项目

本文关键字:项目 列表 另一个 同类型 识别 一个 | 更新日期: 2023-09-27 18:16:57

我需要识别一个列表中没有出现在另一个列表中的项。这两个列表是不同的实体(ToDoWorkshopItem)。如果Name在任何待办事项列表项中匹配,我认为一个车间项目在待办事项列表中。

下面的代码做了我想要的,但每次我重新访问它时都觉得很尴尬,很难理解。我使用NHibernate QueryOver语法来获取两个列表,然后使用LINQ语句来过滤到满足要求的研讨会项目(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,符合我的要求。

识别一个列表中的项目,而不是另一个不同类型的列表中的项目

认为我已经设法把@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。如果有人能给我一些帮助的话。

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

// 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()

我推荐

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))