I'm not going to explain this particularly well, but your problem is that there is nothing to "tie together" all those ExecuteNonQuery statements. Each of them "stands alone" - similar to putting
GO
into a SQL query directly - for example
DECLARE @T VARCHAR(20);
GO
SET @T='Hello World'
will throw an error because @T is not declared by the time you execute the SET. This is the basis of Solution 3 - putting all of the sql into a single ExecuteNonQuery statement is one way around your problem. Putting your sql (including the rollback) into a Stored Procedure is another alternative.
This very good CodeProject article -
Using Transactions in ADO.NET[
^] - explains the concepts far better than I and includes an example solution that will fit right in with what you already have