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

时间:2013-06-05 13:57:26

标签: c# nhibernate

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

以下是我所追求的,但每次重新审视时都会觉得难以理解。我使用NHibernate QueryOver语法来获取两个列表,然后使用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列表。

3 个答案:

答案 0 :(得分:2)

想想我已经设法将@CSL提出的答案的Linq版本放在一起,并将其标记为已接受的答案,因为它使我朝着以下方向发展。< / p>

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。如果有人能对那些有帮助的人有所了解。

答案 1 :(得分:1)

我不是百分百确定如何使用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()

答案 2 :(得分: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))

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