2011-07-14 41 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當然也是正確的。):) –