Home Articles

GroupBy在LINQ to DataSet中

Asked
Viewed 1484 times
1

Background

我将数据从MySQL数据库导入SQL-Server数据库(用于报告,后来用于SSAS-Cube) . 我想同时规范化数据 . 我想将 Ticket_IDs 重复分组到表 Contact 中的一条记录以及其他有用的信息,并将rawdata保留在子表 ContactDetail 中(将foreign键保留为Contact) . 因此 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 -table

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

Question

是否可以通过Ticket_ID对LINQ / LINQ-to-DataSet进行分组,并获取每个ContactRow的ContactDetailRows列表?我知道有一个GroupBy -Extension,但我不确定如何使用,如果它做我需要的(保持ContactDetail-Rows,f.e . 像一个dicitonary与Ticket_ID作为键和 List(of EmailRow) 作为值) .

这就是我所拥有的(简化):

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 :类型化数据集(MySQL)

  • src.email :键入DataTable =>进入 ContactDetail

  • dest :类型化数据集(SQL-Server)

  • dest.Contact 键入的DataTable

  • dest.ContactDetail 键入DataTable,其中fk为 Contact

我更喜欢VB.NET,因为我还不熟悉LINQ,语法在C#中完全不同 .

Edit:

感谢@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的迭代方法更快,以检测联系人是否已经创建 .

2 Answers

  • 1

    我认为使用Lookup(就像一本字典但用密钥/ Collection代替)对你来说是一个很好的解决方案 . 这样的事情:

    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评论我 .

  • 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添加到哈希集,然后通过 Contains 方法检查其存在 . 这比你正在做的要快,但我怀疑LINQ分组会比HashSet快 .

Related