mdk09
mdk09

Reputation: 309

Cannot add same key to dictionary more than once

Here is my code:

IEnumerable<ServiceTicket> troubletickets = db.ServiceTickets.Include(t => t.Company).Include(t => t.UserProfile);
var ticketGroups = new Dictionary<string, List<ServiceTicket>>();

ticketGroups = troubletickets
                .GroupBy(o => o.DueDate).ToDictionary(
                    group => {
                        var firstOrDefault = @group.FirstOrDefault();
                        return firstOrDefault != null
                            ? firstOrDefault.DueDate.HasValue
                                ? firstOrDefault.DueDate.Value.ToShortDateString()
                                : ""
                            : "";
                    },
                    group => group.ToList()
                ).OrderBy(g => g.Key).ToDictionary(g => g.Key, g => g.Value);

The error that I am getting is: 'An item with the same key has already been added.' This is because the DueDate value is occasionally repeated. My question is how can I keep the key from being added if it already exists in the dictionary?

Upvotes: 1

Views: 678

Answers (2)

Gert Arnold
Gert Arnold

Reputation: 109109

You get duplicate keys because there are two ways to get an empty string as key, either an empty group, or an empty date. The duplicate will always be the empty string. I wonder if you really intended to get an empty string as key when the group is empty. Anyway, it's not necessary, you can always filter empty groups later.

It's easier to group by date (including null) first through the database engine and then apply string formatting in memory:

IQueryable<ServiceTicket> troubletickets = db.ServiceTickets
                                             .Include(t => t.Company)
                                             .Include(t => t.UserProfile);

Dictionary<string, List<ServiceTicket>> ticketGroups = 
                troubletickets
               .GroupBy(ticket => ticket.DueDate)
               .AsEnumerable() // Continue in memory
               .ToDictionary(g => g.Key.HasValue 
                                        ? g.Key.Value.ToShortDateString() 
                                        : string.Empty,
                                  g => g.Select(ticket => ticket));

Now the grouping is by the Key value, not by the First element in the group. The Key is never null, it's always a Nullable<DateTime>, with or without a value.

Side note: you'll notice that EF will not generate a SQL group by statement, that's because the SQL statement is "destructive": it only returns grouped columns and aggregate data, not the individual records that a LINQ GroupBy does return. For this reason, the generated SQL is pretty bloated and it may enhance performance if you place the AsEnumerable before the .GroupBy.

Upvotes: 0

D Stanley
D Stanley

Reputation: 152556

It seems that you are grouping by one value (the DueDate value), but using a different value as the dictionary key.

Can you not just use the custom code for grouping instead?

ticketGroups = troubletickets
                .GroupBy(o => o.DueDate.HasValue
                                ? o.DueDate.Value.ToShortDateString()
                                : "")
                .ToDictionary(g => g.Key, g => g.ToList());

Note that I took our the superfluous OrderBy and second ToDictionary call - I assumed you were trying to "order" the dictionary which won't work as a plain dictionary is not ordered.

Upvotes: 1

Related Questions