【问题标题】:Identifying duplicate datatable rows using LINQ使用 LINQ 识别重复的数据表行
【发布时间】:2018-11-13 17:31:13
【问题描述】:

我有一个应用程序,用户在其中输入用于查询数据库并返回匹配行的搜索词。我想找到这样重复的行:

File  Tool  Product  Time1          MeasureTime      Row
319   S32   AX       11/13 1:12AM   11/13 5:02am     5
318   S32   AX       11/13 1:12AM   11/13 4:41am     5

在这些情况下,具有较高文件 ID 的条目可能是错误的重新测量,因此我希望能够向用户突出显示这一点。

如果有重复的行,我有这段代码:

                    var duplicates = db2.AsEnumerable()
                    .GroupBy(r => new
                    {
                        Tool = r.Field<string>("Tool"),
                        Product = r.Field<string>("Product"),
                        Time1 = r.Field<DateTime>("Time1"),
                        Row = r.Field<Int32>("Row")
                    }).Select(g => new {
                        Tool = g.Key.Tool,
                        Product = g.Key.Product,
                        Time1 = g.Key.Time1,
                        Row = g.Key.Row,
                        Count = g.Count() }).ToList();

这将返回一个通用列表,我希望能够从中获取计数并将其添加回初始数据表 db2。然后,当用户选择计数大于 1 的行时,我可以提醒用户。我只想在用户选择更高的文件编号时发出警报,因此我可能需要通过排名来执行此操作,但无论哪种方式,我怎样才能将我拥有的内容添加回原始表格?

【问题讨论】:

  • 是什么让行重复?只是工具和产品名称?
  • 工具、产品、time1(关闭工具的时间)和行。
  • 我很困惑,为什么要将它“添加回”到原始表中,它不是已经存在了吗?
  • 我想将计数(或排名)添加回初始表,以便当用户选择一行时,我可以识别潜在问题。在用户选择要打开的行时,我不想查看它是否与另一行匹配工具/产品/时间/行。
  • 用户执行的操作是否需要连接回初始表?选择一行后会发生什么?

标签: c# linq datatable


【解决方案1】:

如上所述,您需要创建一个新列表,因为您丢失了对原始数据的引用:

var updateList = db2.Where(r=> Tool = r.Field<string>("Tool") 
  && Product = r.Field<string>("Product")
  && Time1 = r.Field<DateTime>("Time1")
  && Row = r.Field<Int32>("Row"));

foreach (var ul in updateList)
  ul.Count = updateList.Count();

或者,如果您从代码中删除 Select,您可以保留对原始数据的引用:

var duplicates = db2.AsEnumerable()
  .GroupBy(r => new
  {
    Tool = r.Field<string>("Tool"),
    Product = r.Field<string>("Product"),
    Time1 = r.Field<DateTime>("Time1"),
    Row = r.Field<Int32>("Row")
  });

foreach (var d in duplicates)  //Iterate through the groups
{
  foreach (var item in d)  //Iterate through the items in a group
  {
    item.Count = d.Count();
  }
}

【讨论】:

  • 我正在尝试第二种方法,但我收到“无法分配给 'Count' 因为它是'方法组'”的错误。我需要先在某个地方声明吗?感谢您的帮助!
  • 您有两个foreach 语句吗?该错误意味着您仍在使用某种IEnumerable,其方法为Count()
  • 是的,我有两个foreach 声明,就像您在答案中显示的那样。嗯……
  • 我想我误解了这个错误。是的,您将需要在您的班级中有一个字段来分配该值。我假设你已经有一个,因为它在你的问题中 (Count = g.Count())
  • 是的,我正在创建计数作为 select 语句的一部分,该语句有效,但我正在寻找一种方法将计数恢复到我的原始数据表,以便我可以继续使用计数。跨度>
【解决方案2】:

显然,您设计可以通过 ToolProduct 等的值来识别度量:如果您有两个具有相同值的项目 ToolProduct 等,它们属于相同的测量组,甚至可能是相同的测量。

为了防止我不得不一遍又一遍地说“相同的工具、产品等”,我将这些属性的集合称为MeasurementId。所以每当我说MeasurementId时,我的意思是属性工具/产品/时间/行

问题描述

如果您使用相同的MeasurementId 进行了两次测量,则它们可能是重新测量。因此,每当操作员选择了其他具有相同MeasurementId 的测量时,您需要警告操作员,如果操作员选择了最旧的测量,则可能不会。

您的问题似乎类似于在数据库中保留多个版本的内容。如果有人将具有与测量结果相同的“MeasurementId. but with a differentFile, it is as if you add a newVersion”的新项目添加到您的数据库中。

如果操作员没有选择最旧的版本,您想警告他。

您选择了以下解决方案:

我希望能够从中获取计数并将其添加回初始数据表 db2

不要添加计数,而是考虑添加“先前版本”的 Id,如果没有先前版本,则添加 0。

class Measurement
{
     public int Id {get; set;}
     public int File {get; set;}

     // measurement identification
     public string Tool {get; set;}
     public string Product {get; set;}
     ...

     // you wanted to add a Count, instead add a previous version
     public int PreviousMeasurementId {get; set;}   // 0 if no previous measurement
}

在添加测量之前检查是否已经有类似的测量:

void AddMeasurement(Measurement measurementToAdd)
{
     var lastMeasurementVersionId = dbContext.Measurements
         .Where( measurement => // select with same measurementId:
             measurement.Tool == measurementToAdd.Tool
             && measurement.Product == measurementToAdd.Product
             && ...)
         // from the remaining versions, keep the one with the highest File:
         .OrderByDescending(measurement => measurement.File)
         // I'm only interested in the Id of this measurement
         .Select(measurement => measurement.Id)
         .FirstOrDefault();

现在,如果已经有类似的测量,lastMeasurementVersionId 是最后一个类似测量的 ID。如果没有,则该值等于 0。

在将 lastMeasurementVersionId 分配给PreviouseMeasurementId 后添加新的度量:

    measurementToAdd.PreviousMeasurementId = lastMeasurementVersionId;
    dbContext.Measurements.Add(measurementToAdd);
    dbContext.SaveChanges();
}

这将如何帮助我解决我的问题?

如果操作员选择Measurement,您唯一需要做的就是检查PreviousMeasurementId 的值。如果为零,则操作员选择了第一个测量,如果不是,您可以警告操作员此测量有多个版本。选择的可能是重新测量。

可能的改进:

  • 考虑为您的复合MeasurementId 添加一个额外的索引。 MeasurementId 的值不会经常更改,但使用此 MeasurementId 获取所有测量值的查询要快得多
  • 如果您对所有版本都没有兴趣,而只对第一个版本感兴趣,请不要记住PreviousMeasurementId,而要记住FirstMeasurementId

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-06-20
    • 2014-09-22
    • 2014-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-05
    相关资源
    最近更新 更多