使用实体框架的棘手的LINQ查询

时间:2014-03-12 10:02:23

标签: c# sql .net linq entity-framework

我一直在研究一些LINQ,我似乎无法弄清楚如何过滤这些数据。我仍然是LINQ的新手,这是我遇到的第一个真正的绊脚石。

我有桌子:

TaskID |名称| TypeID | ParentTaskID

值:

  

1 | TaskName | 1 | NULL

     

2 | TASKNAME | 6 | NULL

     

3 | TASKNAME | 6 | 4

     

4 | TASKNAME | 2 | NULL

     

5 | TASKNAME | 6 | 4

     

6 | TASKNAME | 3 | 4

     

7 | TASKNAME | 6 | 1

     

8 | TASKNAME | 6 | 1

     

9 | TASKNAME | 2 | NULL

SubTask是具有ParentTaskID的任务。

我需要使用此条件获取所有任务:

  • 如果任务没有分配SubTasks且TypeID = 6
  • ,则删除任务
  • 如果ParentTask包含所有TypeID = 6的子任务,则删除父项和子任务

因此我希望能够回来

  

3 | TASKNAME | 6 | 4

     

4 | TASKNAME | 2 | NULL

     

5 | TASKNAME | 6 | 4

     

6 | TASKNAME | 3 | 4

     

9 | TASKNAME | 3 | NULL

上表中的结果如下:

  

删除了TaskID 1,因为TaskID 7& 8是SubTasks,TypeID = 6

     

删除了TaskID 2,因为它没有SubTasks且TypeID = 6

     

TaskID 7& 8被删除,因为它们是ParentTask,TypeT = 6,用于ParentTask 1

甚至可以在LINQ中执行此操作,还是必须驻留在foreach循环中执行此操作?

我的解决方案

所以我最终以Foreach的老式方式做了这件事,让Resharper将它可以转换回LINQ。

        var parents = tasks.Where(task => task.SubTasks.Any());
        var tasksWithNoSubs = tasks.Where(task => !task.SubTasks.Any());
        var parentIdsToRemove = new List<int?>();
        var childIdsToRemove = new List<int?>();

        foreach (var parent in parents)
        {
            var children = tasks.Where(task => task.ParentTaskID == parent.Id);
            if (children.All(task => task.StatusId == 6))
            {
                parentIdsToRemove.Add(parent.Id); //mark this parent for removal
                childIdsToRemove.AddRange(Enumerable.Select(children.Select(child => child.Id), dummy => (int?) dummy));
            }
        }

        //get all Tasks that have NO Subtasks and also have a StatusID = 6
        parentIdsToRemove.AddRange(Enumerable.Select((from task in tasksWithNoSubs where task.StatusId == 6 select task.Id), dummy => (int?) dummy));

        //get a list of children with an Id contained in the list parentIdsToRemove
        var tasksToRemove =
            tasks.Where(task => parentIdsToRemove.Contains(task.Id) || childIdsToRemove.Contains(task.Id));

        //remove the tasks from the collection
        tasks = tasks.Where(task => !tasksToRemove.Contains(task));

3 个答案:

答案 0 :(得分:-1)

您应该直接在您的任务对象上生成属性(由实体框架生成,其中包括对父/子的引用,我假设父文件名为ParentTask,子项在我的示例中命名为Tasks,相应地重命名。 #39; t想要使用ID这是非常不同的EF,EF&amp; linq的全部意义在于让它处理所有数据库非规范化无意义并使用对象图。

YourContext.Tasks
    // Only keep those where it isn't true that it contains no tasks while being type 6
    .Where(t=>!((!t.Tasks.Any()) && t.TypeId == 6))
    // Remove all parents that contains subtasks and only have subtasks with type 6
    .Where(t=>!(t.Tasks.Any() && t.Tasks.All(sub=>sub.TypeId == 6)))
    // Same process on the children, if it has a parent and that parent matches the previous filter
    .Where(t=>!(t.ParentTask != null &&(t.ParentTask.Tasks.Any() && t.ParentTask.Tasks.All(sub=>sub.TypeId == 6))))

请注意,这是完全未经测试的,如果它不起作用,请提供指向已编译模型DLL的链接

答案 1 :(得分:-1)

请参阅原始帖子中的解决方案(也在此处发布)。

    var parents = tasks.Where(task => task.SubTasks.Any());
    var tasksWithNoSubs = tasks.Where(task => !task.SubTasks.Any());
    var parentIdsToRemove = new List<int?>();
    var childIdsToRemove = new List<int?>();

    foreach (var parent in parents)
    {
        var children = tasks.Where(task => task.ParentTaskID == parent.Id);
        if (children.All(task => task.StatusId == 6))
        {
            parentIdsToRemove.Add(parent.Id); //mark this parent for removal
            childIdsToRemove.AddRange(Enumerable.Select(children.Select(child => child.Id), dummy => (int?) dummy));
        }
    }

    //get all Tasks that have NO Subtasks and also have a StatusID = 6
    parentIdsToRemove.AddRange(Enumerable.Select((from task in tasksWithNoSubs where task.StatusId == 6 select task.Id), dummy => (int?) dummy));

    //get a list of children with an Id contained in the list parentIdsToRemove
    var tasksToRemove =
        tasks.Where(task => parentIdsToRemove.Contains(task.Id) || childIdsToRemove.Contains(task.Id));

    //remove the tasks from the collection
    tasks = tasks.Where(task => !tasksToRemove.Contains(task));

感谢大家的贡献,def学到了很多关于LINQ的知识。

答案 2 :(得分:-3)

第二次非常大的编辑

右键!所以,经过很长一段时间和一些误解后第三次幸运 - 这里有一个声明:

entities.

// discard tasks of type 6 and with no subtasks
Where(x => !(x.TypeId == 6 && x.ParentTaskId == null && 
      !entities.Any(y => y.ParentTaskId == x.TaskId))).

// discard tasks with subtasks where all those subtasks are of type 6
Where(x => !(entities.Any(y => y.ParentTaskId == x.TaskId) &&
             entities.Count(y => y.ParentTaskId == x.TaskId) ==
             entities.Count(y => y.ParentTaskId == x.TaskId && y.TypeId == 6))).

// discard subtasks that have parents that are not to be found in the list of 
// tasks that were not discarded for having subtasks that were all of type 6.
Where(z => z.ParentTaskId == null || 
             entities.Where(x => !(entities.Any(y => y.ParentTaskId == x.TaskId) &&
                                   entities.Count(y => y.ParentTaskId == x.TaskId) ==
                                   entities.Count(y => y.ParentTaskId == x.TaskId && y.TypeId == 6))).
                                            Any(y => y.TaskId == z.ParentTaskId));