Grouping creates keyed sequences, not a single total
GroupBy partitions observations according to a selected key. In this lesson the key is IsPaid, a boolean property of each Order. The result is a sequence of groups, and every group contains a key plus the original orders that share it. Grouping alone does not add monetary amounts. A later aggregate must choose which group's observations to combine and which numeric property each order contributes to that calculation.
The Order record is supplied by the project's Models/Order.cs file and contains Id, Amount, and IsPaid. Keep that file when opening the example as a project; adding another Order declaration to Program.cs can create a type conflict instead of helping the query. The input deliberately includes both paid and unpaid observations. That lets you compare the membership of the groups and see why a report over one group is different from a sum over the entire source.
Select the true-key group before summing
The three orders have amounts ten, four, and two. The first two have IsPaid equal to true, while the last has it equal to false. GroupBy therefore produces a true-key group containing the first two orders and a false-key group containing the third. First(g => g.Key) searches for the group whose boolean Key is true. The predicate is not choosing the first order, and it is not treating a monetary amount as a boolean.
The selected paid group then supplies its Amount values to Sum: ten plus four is fourteen. WriteLine prints 14, with no separate line for the unpaid group. For this in-memory LINQ operation, GroupBy builds the grouping information when enumeration starts; it should not be described as a guarantee that only the first paid row is read. Grouping preserves the original observations for each group so a group can support further calculations, such as a count, after selection.
var paid = orders.GroupBy(o => o.IsPaid).First(g => g.Key);
Console.WriteLine(paid.Sum(o => o.Amount));A missing paid group is not an empty paid group
If every order is unpaid, GroupBy creates no true-key group. First with the predicate then throws because there is no matching group. That is a different contract from filtering paid orders and summing an empty decimal sequence, which returns zero. Choose the behavior the report needs rather than assuming these formulations are interchangeable for every input. If the task only needs a paid total, Where followed by Sum may express it more directly; GroupBy is useful when several groups or several group-level facts matter.
Make both groups visible, then remove a group
First replace the single-group selection with a loop over every group. Print its Key, Count, and amount sum. Predict true with two orders totaling fourteen, and false with one order totaling two; choose an explicit display order if the report requires one. Hint: a group is itself enumerable, so Count and Sum apply to its members while Key describes the common classification, not a field copied from a selected order.
Next set every IsPaid value to false and run the unchanged First-based query as a controlled failure exercise. Explain why there is no matching group. Then implement a paid-total formulation that intentionally returns zero when no orders qualify. Hint: decide whether absence is exceptional before choosing First, FirstOrDefault, Where, or a lookup. Finally make one formerly unpaid order paid and predict the new membership counts and total before executing the modified project.
Check key, membership, selection, and aggregate separately
Explain the query as four decisions: derive each key, form the groups, choose the required group, and aggregate its Amount values. Name the multi-file model dependency when sharing the example. A useful test set includes both statuses, only one status, and no orders. Those inputs reveal whether the application wants a missing-group exception, an explicit absent result, or a zero total instead of letting one successful mixed batch choose the policy accidentally.
- Group keys are boolean IsPaid values, not order amounts.
- The true-key group contains amounts ten and four.
- The unchanged project prints
14. - No paid observations means First has no matching group.
A working example
var orders = new[] { new Order("a", 10m, true), new Order("b", 4m, true), new Order("c", 2m, false) };
var paid = orders.GroupBy(o => o.IsPaid).First(g => g.Key);
Console.WriteLine(paid.Sum(o => o.Amount));Expected output
14
Try the filter on a smaller list.