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

发布于 2024-08-13 02:04:48 字数 1597 浏览 5 评论 0原文

绝对是 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)

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

class Trigger
{  
    string Name { get; }
}  

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

class QuartzJob
{
    public QuartzJob(Guid groupId, Guid jobId, IEnumerable<string> triggerNames)
}

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

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;
}

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

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

谢谢!

Definitely a LINQ newbie, but very experienced with SQL and C# and wondering if this is possible in LINQ. If so, I could use it other places, but I figured this would be a good starting point (and help to simplify/clean up some code). This could be more generalized, but I figured this might be a good real-life example that could help explain.

Quick background: I'm doing a personal learning project building a scheduler and learning Spring.NET/DI, Fluent NHibernate, Quartz.NET, and trying to get my feat wet with TDD. Learned a ton so far.

A Quartz.NET IScheduler object has these property(1)/methods(2) (assume public)...

string[] JobGroupNames { get; }
string[] GetJobNames(string groupName)
Trigger[] GetTriggersOfJob(string jobName, string groupName)

Assume Trigger definition is just...

class Trigger
{  
    string Name { get; }
}  

I have a class I'm trying to get a list of which has a constructor like the following (because it's immutable once created)...

class QuartzJob
{
    public QuartzJob(Guid groupId, Guid jobId, IEnumerable<string> triggerNames)
}

Currently this is how I'm handling it...

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;
}

This way works fine (albeit maybe a little slow and complex), but those double foreach loops bug me and since I'm a "learn LINQ" kick, I thought this would a good chance and attempt to apply it.

Not asking for someone to write the code for me, as this is a learning project (although you are more then welcome to), just trying to see if LINQ can do things like this, and if so, looking for some more information on it... Method calls with query values, and use those values to build another query. If so, it would reduce some of my multiple foreach loops I have in other places in my code.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

醉生梦死 2024-08-20 02:04:48

在 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);
}

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

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

The key to doing this in LINQ is to understand that .Select is your friend--but a surly friend who might hit you. I kid. You can use Select and it's cousin SelectMany to transform your arrays on the fly.

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

Or, if you prefer the inline query language it'd be a bit more readable and look like this:

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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文