An older version of re-store required the programmer to discard the client transaction explicitly, thereby handing over the transaction and its domain object instances to the garbage collector. This is what the API for discarding a client transaction looks like:

myClientTransaction.Discard (); // discards my client transaction

Note that we have not used this method in the PhoneBook.Sample. Simple! However, the explicit use of the Discard() is strongly discouraged. There is a better, more modern way. In the old days (until 2007), if the programmer forgot to discard client transactions, they were piling up, clogging resources. This sensitivity to absent minds resembles memory leaks in languages without garbage collection. (malloc() without free() in C, for example, or new without delete in C++).

Enter transaction scopes.

A transaction scope is designed to look and feel like the scope of a method in C#. The scope of local variables of the method is limited to the space between the curly braces:

Transaction scopes work in a similar fashion. The programmer puts up a transaction scope when creating the client transaction. You have seen this already in the section with the PhoneBook report generators (PhoneBook.Sample, Enhancing and using the PhoneBook.Domain library). Remember the construction

using(ClientTransaction.CreateRootTransaction().EnterDiscardingScope())
{
        // lots of domain object code here
        ClientTransaction.Current.Commit();
}

This scope limits the life of the scoped transaction to the space between the curly braces. When the scope is left, the client transaction is discarded automatically, just like a local variable is removed from the call stack when the function (or method) is left. The most interesting detail here is that ClientTransaction.Current always holds the client transaction instance that has been created for the scope ClientTransaction.Current is in. The using and its delimiting braces limit the scope of the transaction created for the using:

The call chain

ClientTransaction.CreateRootTransaction().EnterDiscardingScope()

is the most typical way of creating transactions and a corresponding transaction scope:

A discarding scope is a transaction scope that behaves as explained here: it makes the transaction that belongs to the scope vanish without a trace as soon as execution of the program leaves the scope. (The alternative is FIXME.)

Note how easy it is to answer the following questions for the illustrated listing above:

As explained in the section FIXME above, root transactions are not all there is to it. Sub-transactions are created with the method CreateSubTransaction. This method is not static, however, it is a member of the given client transaction instance. For spawning a sub-transaction from a given client transaction, just call its CreateSubTransaction() method. Call EnterDiscardingScope() like you do for a root transaction.
This works for arbitrarily nested transactions and sub-transactions. Here is a more complicated illustration:

Sub-transactions can be spawned and nested to arbitrary depth:

using (ClientTransaction.CreateRootTransaction().EnterDiscardingScope())
{
  using (ClientTransaction.Current.CreateSubTransaction().EnterDiscardingScope())
  {
    using (ClientTransaction.Current.CreateSubTransaction().EnterDiscardingScope())
    {
      using (ClientTransaction.Current.CreateSubTransaction().EnterDiscardingScope())
      {
        using (ClientTransaction.Current.CreateSubTransaction().EnterDiscardingScope())
        {
          ... more, if you want... 
        }
      }
    }
  }
}