我需要识别一个列表中不存在于另一个列表中的项目。这两个列表具有不同的实体(ToDo
和WorkshopItem
)。如果在任何待办事项列表项中匹配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
列表。
答案 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))
后者对我来说似乎不那么冗长。