Re: "Zombie transaction"?
Databases avoid re-use of identity values, so that the data is protected - if they were re-used then you could accidentally work with the wrong record more easily (eg: you create a new record and print it out, then rollback, but somebody uses the printed copy to update the record that doesn't exist any more - instead they update the replacement record).
The numbers will get re-used eventually (if all other available numbers are used), but after a much longer time, so the chances of problems caused by re-use is dramatically reduced.
Does any data get added to the table? Based on what you've said I suspect not, in which case I would recommend ignoring it.
While you can force the database system to re-use the numbers as soon as possible, the default behaviour is actually a good thing (and doesn't cause problems, except gaps in the numbers which can occasionally cause questions/confusion/etc like you have now).
Re: "Zombie transaction"?
Personally I'd either use DB transaction or code transactions... but not both. Pick one or the other as your standard and stick with it.
ExecuteScalar returns the first value of the first row... which comes from a select. If you use RETURN to return a value, you have to add an additional parameter with a .Direction of ReturnValue to get to the value.
-tg