2011-07-14 124 views
1

背景的GroupBy在LINQ到DataSet中

我从MySQL数据库导入数据到SQL-Server数据库(报告和后来SSAS-立方)。我想同时标准化数据。我想将Ticket_IDs重复与表Contact中的一个记录与其他有用的信息分组,并将原始数据保留在子表ContactDetail(外键联系人)。因此Contact中的每条记录都有一个独特的Ticket_ID

我决定使用强类型数据集进行导入。现在我想知道检测我是否已经添加了Ticket_ID的最佳方法。我可以在每个循环中检查它(~100000条记录),但我假设有一个更好/更快的方法。

简化的抽样数据:

Ticket_ID ID  fiContact 
89442226  1  1 
89442226  2  1 
89442226  3  1 
89442261  4  2 
89442261  5  2 
89442354  6  3 
89442359  7  4 
89442359  8  4 
89442367  9  5 
89442504  10  6 

这应该是Contact - 表

Ticket_ID idContact 
89442226  1 
89442261  2 
89442354  3 
89442359  4 
89442367  5 
89442504  6 

问题

是否有可能与LINQ/LINQ到DataSet中按Ticket_ID分组,并获取每个ContactRow的ContactDetailRows列表?我知道有一个GroupBy-Extension,但我不确定如何使用,如果它确实需要(保留ContactDetail-Rows,f.e.就像Ticket_ID作为键和作为值的List(of EmailRow)的dicitonary一样)。

这是我(简化):

For Each srcEmail In src.email 'i want to group src.email by Ticket_ID' 
     'so far i check for existence in every loop' 
     Dim res = From c In dest.Contact 
       Where c.Ticket_ID = srcEmail.ticket_id 
     If Not res.Any Then 
      'create new Contact 
      Dim newContact = Me.dest.Contact.NewContactRow 
      newContact.Ticket_ID = srcEmail.ticket_id 
      ' ..... ' 
      dest.Contact.AddContactRow(newContact) 
     End If 
     'TODO: create ContactDetail row and add it to the DataTable ' 
    Next 
  • src:类型DataSet(MySQL的)
  • src.email:类型DataTable =>成ContactDetail
  • dest:类型DataSet(SQL-服务器)
  • dest.Contact typed DataTable
  • dest.ContactDetail类型的DataTable与FK到Contact

我宁愿VB.NET,因为我还没有不熟悉LINQ和语法在C#中完全不同。

编辑:

由于@Magnus我得到它通过以下方式去:

Dim emailsPerTicketID = src.email.ToLookup(Function(email) email.ticket_id) 
For Each ticket In emailsPerTicketID 
    'create new Contact 
    Dim newContact = Me.dest.Contact.NewContactRow 
    newContact.Ticket_ID = ticket.Key 
    newContact.CreatedAt = ticket.First().modified_time 
    ' ...... ' 
    dest.Contact.AddContactRow(newContact) 
    'TODO: add now all EmailRows' 
    For Each emailRow In ticket 
     Dim newContactDetail = dest.ContactDetail.NewContactDetailRow 
     newContactDetail.ContactRow = newContact 
     newContactDetail.Interaction = emailRow.interaction 
     ' .... ' 
     dest.ContactDetail.AddContactDetailRow(newContactDetail) 
    Next 
Next 

我会看看,如果这是比一个HashSet的迭代方法快检测联系人是否已经创建。

回答

1

我认为使用Lookup(就像字典,但用键/集合来代替)会是一个很好的解决方案。这样的事情:

var lookup = ds.Tables["src"].AsEnumerable().ToLookup(x => x.Field<int>("Ticket_ID")); 
foreach (var row in ds.Tables["dest"].AsEnumerable()) 
{ 
    if(!lookup.Contains(row.Field<int>("Ticket_ID "))) 
    { 
     //create new Contact 
    } 
    else 
    { 
     //do other struff 
    } 
} 

如果您需要任何帮助翻译任何语法到VB评论我。

+0

谢谢。我自己已经将它转换为VB.NET/type'DataSet'(请参阅我的编辑)。我会测试这是否比迭代更快,并检查像马特建议的HashSet。查找正是我正在寻找。 –

+0

@Tim太棒了!让我知道你的测试结果如何。 – Magnus

1

我的VB是生锈的,但这里的一口吧:

Dim ticketGroups = From c in dest.Contact 
        Group c By Ticket_ID = c.Ticket_ID 
        Into Tickets = Group 

For Each ticketGroup In ticketGroups 
    For Each ticket in ticketGroup.Tickets 
     ' Create the row, add it, etc. 
     Dim newContact = Me.dest.Contact.NewContactRow 
     newContact.Ticket_ID = ticketGroup.Ticket_ID 
     ' .... ' 
     dest.Contact.AddContactRow(newContact) 
    Next 
Next 

另外,如果您想通过循环每次检查它,你可以使用一个HashSet,只需添加票ID的hashset每次通过,然后通过Contains方法检查其存在。这会比你正在做的更快,但我怀疑LINQ分组将比HashSet更快。

+0

谢谢。但是,根据Ticket_ID将所有电子邮件行分组为唯一的电子邮件行。我需要的是一种通过Ticket_Id对这些行进行分组的方式,但保留所有行,例如以'Ticket_ID'为键和'(EmaiRows)列表'作为值的字典。正是@Magnus [Lookup](http://msdn.microsoft.com/zh-cn/library/bb460184.aspx)的做法。 –

+0

对不起,我的示例代码没有说清楚,但它_does_保留所有行。检查ticketGroup.Tickets属性。我将编辑代码。 (Magnus当然也是正确的。):) –