【问题标题】:Linq retrieving items that have changed between sets and items not in setsLinq 检索在集合和不在集合中的项目之间已更改的项目
【发布时间】:2011-10-07 18:54:38
【问题描述】:

这是我的课程:

public class XDetail
{
    public string Name { get; set; }
    public int ID { get; set; }
}

public class X
{
    public int XID { get; set; }
    public int ID { get; set; }
}

ID 在它们之间共享以链接 X 和 XDetail(一对多关系),并且 X 和 XDetail 是真正类型化的 DataRows。我使用以下 linq 查询读取了一个文件并塑造了一个匿名类型:

var results = (from line in File.ReadAllLines(file)
              select new
              {
                  XID = int.Parse(line.Substring(0, 8).TrimStart('0')),
                  Name = line.Substring(8, 255).Trim()
              }).ToList();

此数据用于检查现有 X/XDetail 以进行适当更改或添加新记录。当序列没有结果时,我将结果包装在检查中以查看它是否在 .ToList() 上抛出。 XList 是一个 List,XDetailList 是一个 List。

从那里我尝试一个花哨的 linq 查询来匹配适当的项目:

var changedData = from x in XList
                  join xDetail in XDetailList on x.ID equals xDetail.ID
                  where 
                  (!results.Any(p => p.XID.Equals(x.XID))
                  || !results.Any(p => p.Name.Equals(xDetail.Name)))                   
                  select new
                  {                       
                      XValue = x,
                      XDetailValue = xDetail,
                      Result = (from result in results
                               where result.Name.Equals(xDetail.Name)
                               select result).SingleOrDefault()
                  };

我的新问题是这个查询只会为我提供 X/XDetail 中的变化,而不是新的。为了获得新的东西,我必须运行另一个查询,这在测试小数据集(X/XDetail 的 3 个现有条目)时似乎足够好,但是当我尝试真正的文件并翻阅它时,我似乎有大约 7700 个条目进行无休止的处理。

对于已包含在 X/XDetail 中的以下示例数据集:
XID:1,姓名:Bob,ID:10
XID:2,姓名:Joe,ID:20
XID:3,姓名:Sam,ID:30

结果文件包含:
XID:2,姓名:Bob2
XID:3,姓名:NotSam
XID:4,姓名:NewGuy
XID:5,姓名:NewGuy2

我希望能够获得包含以下内容的结果集:
{XID: 2, 姓名: Bob2}, x, xDetail
{XID: 3, 名称: NotSam}, x, xDetail
{XID: 4, 姓名: NewGuy}, x, xDetail
{XID: 5, 姓名: NewGuy2}, x, xDetail

我希望 x 和 xDetail 作为结果集的一部分,以便我可以使用这些类型的数据行进行必要的更改。

我尝试过这样的查询:

var newData = from result in results
              join x in XList on result.XID equals x.XID
              join xDetail in XDetailList on x.ID equals xDetail.ID
                      where
                      (x.XID == result.XID && xDetail.Name != result.Name)
                      select new
                      {
                          XValue = x,
                          XDetailValue = xDetail,
                          Result = result
                      };

由于连接表明我只会获取数据中的更改项,我真的希望能够添加不在 X/XDetail 中的数据并停止一直在处理我的系统过去 2.5 小时 ~7700 次更改文件。我觉得我已经盯着这个和相关的查询太久了,无法发现我应该做些什么来正确地为它塑造一个 where 子句。

有没有办法构造 linq 查询以查找更改的数据和 X/XDetail 中不存在的数据并将其返回到新的结果集中进行处理?

【问题讨论】:

  • 有没有办法构造 linq 查询以查找更改的数据和 X/XDetail 中不存在的数据并将其返回到新的结果集中进行处理?

标签: c# linq linq-to-objects


【解决方案1】:

我认为您的性能问题与查询的复杂性有关,可能在 O(n^2) 左右。

因此,首先我建议您将当前数据设置在查找结构中,如下所示(*):

var joinedByXID = (from x in XList
                    join xDetail in XDetailList on x.ID equals xDetail.ID
                    select new { X = x, XDetail = xDetail })
                    .ToLookup(x => x.X.ID);

现在,我不确定,但我假设说“更改的数据”是指具有 XID 已经存在但新名称的条目列表,对吗?
如果是这样,您可以使用此查询获取“更改的数据”:

var changedData = results
.Where(r => joinedByXID.Contains(r.XID))
.SelectMany(r => joinedByXID[r.XID]
            .Where(x => x.XDetail.Name != r.Name)
            .Select(old => new {XValue=old.X, XDetailValue=old.XDetail, Result=r}));

然后,如果“新数据”是指具有新 XID 的条目列表(XID 当前不存在于 XList/XDetailList 中),那么您不能将它们与 X/Xdetail 元素匹配,因为没有任何,这很简单:

var newData = results
.Where(r => !joinedByXID.Contains(r.XID));

(*)
实际上,为了更快,您可以将数据排列在字典中,其中外键是 XID,内键是名称。

【讨论】:

    猜你喜欢
    • 2010-11-04
    • 1970-01-01
    • 2011-12-06
    • 1970-01-01
    • 2013-12-21
    • 1970-01-01
    • 2019-09-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多