使用LINQ查询/子查询多个方法(Quartz.NET示例用于组,作业和触发器)

Ste*_*ter 2 c# linq subquery quartz-scheduler quartz.net

绝对是一个LINQ新手,但对SQL和C#非常有经验,并想知道这在LINQ中是否可行.如果是这样,我可以在其他地方使用它,但我认为这将是一个很好的起点(并有助于简化/清理一些代码).这可能更通用,但我认为这可能是一个很好的现实生活中的例子,可以帮助解释.

快速背景:我正在做一个个人学习项目,构建一个调度程序,学习Spring.NET/DI,Fluent NHibernate,Quartz.NET,并尝试用TDD来完成我的专长.到目前为止已经学到了一吨.

Quartz.NET IScheduler对象具有这些属性(1)/方法(2)(假设为公共)...

string[] JobGroupNames { get; }
string[] GetJobNames(string groupName)
Trigger[] GetTriggersOfJob(string jobName, string groupName)
Run Code Online (Sandbox Code Playgroud)

假设触发器定义只是......

class Trigger
{  
    string Name { get; }
}  
Run Code Online (Sandbox Code Playgroud)

我有一个类我正在尝试获取一个列表,其中包含如下构造函数(因为它一旦创建就不可变)...

class QuartzJob
{
    public QuartzJob(Guid groupId, Guid jobId, IEnumerable<string> triggerNames)
}
Run Code Online (Sandbox Code Playgroud)

目前这就是我处理它的方式......

public IEnumerable<QuartzJob> GetQuartzInfo(IScheduler scheduler)
{
    List<QuartzJob> list = new List<QuartzJob>();

    foreach (string grp in scheduler.JobGroupNames)
    {
        foreach (string job in scheduler.GetJobNames(grp))
        {
            var triggerNames = scheduler
                .GetTriggersOfJob(job, grp)
                .ToList()
                .ConvertAll(t => t.Name);

            var qj = new QuartzJob(new Guid(grp), new Guid(job), triggerNames);
            list.Add(qj);
        }
    }    
    return list;
}
Run Code Online (Sandbox Code Playgroud)

这种方式工作正常(虽然可能有点慢和复杂),但那些双foreach循环让我感到烦恼,因为我是"学习LINQ"踢,我认为这是一个很好的机会并尝试应用它.

不要求有人为我编写代码,因为这是一个学习项目(尽管你更受欢迎),只是想看看LINQ是否可以做这样的事情,如果有的话,寻找更多的信息...使用查询值调用方法,并使用这些值构建另一个查询.如果是这样的话,它会减少我在代码中其他地方的一些foreach循环.

谢谢!

Jac*_*itt 5

在LINQ中做到这一点的关键是要明白.Select是你的朋友 - 但是一个可能会打你的朋友.我小子 你可以使用Select和它的堂兄SelectMany来动态转换你的数组.

public IEnumerable<QuartzJob> GetQuartzInfo(IScheduler scheduler)
{
    IEnumerable<QuartzJob> jobs = scheduler.JobGroupNames.SelectMany(   // Using SelectMany because there is an IEnumerable<QuartzJob> for each group and we want to flatten that.
        groupName => scheduler.GetJobNames(groupName).Select(  // Returns an IEnumerable<QuartzJob> for each group name found.
            jobName => 
                // We're doing a lot in this new but essentially it creates a new QuartzJob for each jobName/groupName combo
                new QuartzJob(new Guid(groupName), new Guid(jobName),
                    scheduler.GetTriggersOfJob(jobName, groupName).Select(trigger => trigger.Name)  // This transforms the GetTriggersOfJob into an IEnumerable<string> for use in the constructor of QuartzJob
                    ))); 
    return new List<QuartzJob>(jobs);
}
Run Code Online (Sandbox Code Playgroud)

或者,如果您更喜欢内联查询语言,它会更具可读性,如下所示:

public IEnumerable<QuartzJob> GetQuartzInfo(IScheduler scheduler)
{
    IEnumerable<QuartzJob> jobs = from groupName in scheduler.JobGroupNames
                                  from jobName in scheduler.GetJobNames(groupName) // stacking the two froms is the equivalent of SelectMany because the first select is defaulted as the result of the second.
                                  select new QuartzJob(new Guid(groupName), new Guid(jobName),
                                      // this sub-select is to get just the IEnumerable<string> of trigger names needed for the constructor.
                                      (from trigger in scheduler.GetTriggersOfJob(jobName, groupName)
                                       select trigger.Name));
    return new List<QuartzJob>(jobs);
}
Run Code Online (Sandbox Code Playgroud)