【问题标题】:Combine two LINQ queries from different sources into single object将来自不同来源的两个 LINQ 查询合并到单个对象中
【发布时间】:2012-11-12 12:19:20
【问题描述】:

我正在从两个不同的来源收集数据,目的是填充单个对象。我的课是

public class SampleClient
{
    public string ClientId { get; set; }
    public string JobName { get; set; }
    public string JobUrl { get; set; }
    public string Version { get; set; }
}

第一个 LINQ 查询填充 SampleClient 对象的集合,获取除 Version 之外的所有对象的值。然后我需要遍历SampleClient 的集合并在第二个查询中使用ClientId 值。第二个查询的结果是版本值。这是我的第一个 LINQ 查询:

    private void btnProjects_Click(object sender, EventArgs e)
    {
        string[] stringArray = { "demo", "sample", "test", "training" };
        List<SampleClient> jobList =
        (
            from x in XDocument.Load(XML URL VALUE HERE).Root.Elements("job")
            where x.Element("name").Value.Contains("-config") && x.Element("name").Value.StartsWith("oba-")
            && (!stringArray.Any(s => x.Element("name").Value.Contains(s)))
            select new SampleClient
            {
                ClientId = getClientId((string)x.Element("name")),
                JobName = (string)x.Element("name"),
                JobUrl = (string)x.Element("url"),
            }).ToList();

        foreach (SampleClient job in jobList)
        {
            //Display the results in a textbox
            txtResults.Text += "Job Name = " + job.JobName + " | Job URL = " + job.JobUrl + " | ";
        }
    }

在获取版本的查询中,我目前有:

var version = from item in doc.Descendants(ns + "properties")
select new SampleClient
{
    ClientId = strClientId,
    Version = (string)item.Element(ns + "product.version").Value
};

请务必注意,第二个查询中使用的 URL 源是使用从第一个查询中获得的 ClientId 创建的。我可以有一个例行的循环和清理/合并对象,但这感觉就像一个黑客。有没有更清洁的方法来处理这个问题?

这是来自第一个查询的 XML 示例:

<?xml version="1.0"?>
<allView>
    <description>PROD</description>
    <job>
        <name>abc</name>
        <url>http://ci-client.company.net/job/abc/</url>
        <color>blue</color>
    </job>
    <job>
        <name>acme</name>
        <url>http://ci-client.company.net/job/acme/</url>
        <color>blue</color>
    </job>
</allView>

第二个查询 URL 是使用第一个查询结果中的 clientID 动态创建的。我正在使用它来加载 Maven POM 文件并获取版本信息。这是来自 POM 文件的 XML 的 sn-p。

<?xml version="1.0" encoding="UTF-8" ?> 
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion> 
    <groupId>com.company.xyz</groupId> 
    <artifactId>io</artifactId> 
    <version>6.11.7-ACME-SNAPSHOT</version> 
    <packaging>pom</packaging> 
    <properties>
        <product.version>6.11.7</product.version> 
        <db.version>1.4</db.version> 
    </properties>
    <modules>
        <module>policies</module> 
        <module>templates</module> 
        <module>assemble</module> 
    </modules>
</project>

【问题讨论】:

  • 第二个查询中strClientId是从哪里来的?
  • 目的(虽然还没有完全发挥作用)是它来自于循环遍历第一个查询的结果。换句话说,它是第一个查询创建的 SampleClient 集合中的 ClientId。我希望这是有道理的。
  • 显示一个 XML 源示例。
  • 如果您从已经创建的 sampleClient 传递 strClinetId,那么只需传递对象并将版本直接放在对象上。
  • 虽然我不明白第二个查询,但从您所说的来看,您是在暗示您有一个strClientId,并且该查询暗示了许多版本.....

标签: c# linq


【解决方案1】:

希望我能理解你的问题..

这会将它们合并在一起(尽管我的测试数据只有 ClientId、JobName 和 Version..)。 Query 1 包含 ClientId 和 JobName,Query2 包含 ClientId 和 Version。

IList<SampleClient> mergedList = firstQuery.Concat(secondQuery)
    .ToLookup(x => x.ClientId)
    .Select(x => x.Aggregate((query1, query2) => 
            new SampleClient() { 
                    ClientId = query1.ClientId, 
                    JobName = query1.JobName,
                    Version = query2.Version 
                }
            )
    ).ToList();

.. 可能不如您的手动方法高效.. 但是我没有什么可作为基准的..

【讨论】:

  • 感谢您的快速反馈。我认为你理解我的问题,我会在早上试试这个。由于我是 LINQ 的新手,我不得不问一个可能是愚蠢的问题。您引用了 firstQuery、secondQuery 以及 query1 和 query2。你能帮我把这些定义的地方拼凑起来吗?再次感谢。
  • firstQuerysecondQuery 只是您在问题中提到的两个查询的占位符。我用虚拟数据预先填充了占位符。 query1query2 是聚合用于构建返回列表的单个项目。
【解决方案2】:

试试这个:

var jobList = from x in XDocument.Load(...
              where ...
              let clientId = getClientId((string)x.Element("name"))
              select new SampleClient
              {
                  ClientId = clientId,
                  JobName = (string)x.Element("name"),
                  JobUrl = (string)x.Element("url"),
                  Version = (string)XDocument
                      .Load(GetSecondQueryUrl(clientId))
                      .Root
                      .Element(pom4 + "properties")
                      .Element(pom4 + "product.version")
              };

【讨论】:

  • 谢谢 dtb。我会在早上尝试。假设这可行,它肯定比我想象的要干净。我真的需要学习这些 LINQ 的东西!
猜你喜欢
  • 1970-01-01
  • 2017-04-14
  • 1970-01-01
  • 2012-02-18
  • 2020-01-10
  • 2013-11-22
  • 1970-01-01
  • 1970-01-01
  • 2018-04-08
相关资源
最近更新 更多