//by lostinet.com
using System;
using System.Collections;
using System.Data.SqlClient;namespace ct
{
public class SqlScopeException:Exception
{
public SqlScopeException(string message)
:base(message)
{
}
public SqlScopeException(string message,Exception innerException)
:base(message,innerException)
{
}
}
/// <summary>
/// 通过传递SqlScope,实现SqlConnection,SqlTransaction的创建,起用,传递和释放
/// </summary>
public class SqlScope:IDisposable
{
string connString;
SqlConnection conn=null;
SqlTransaction trans=null;
Stack stack=null; public SqlConnection Connection
{
get
{
CheckConnection();
return conn;
}
}
public SqlTransaction Transaction
{
get
{
CheckConnection();
return trans;
}
}
public string ConnectionString
{
get
{
return connString;
}
}
static public implicit operator SqlConnection (SqlScope ss)
{
return ss.Connection;
}
static public implicit operator SqlTransaction (SqlScope ss)
{
return ss.Transaction;
} public SqlScope(string ConnectionString)
{
if(ConnectionString==null)
throw(new ArgumentNullException("ConnectionString"));
connString=ConnectionString;
}
~SqlScope()
{
Dispose();
}
public void Dispose()
{
stack=null;
try
{
if(trans!=null)
trans.Dispose();
}
finally
{
try
{
if(conn!=null)
conn.Dispose();
}
finally
{
conn=null;
trans=null;
}
}
}
void OpenConnection(bool beginTransaction)
{
if(stack!=null)
throw(new SqlScopeException("Connection已经被打开!"));
stack=new Stack();
conn=new SqlConnection(connString);
conn.Open();
if(beginTransaction)
trans=conn.BeginTransaction("trans");
}
void CheckConnection()
{
if(stack==null)
throw(new SqlScopeException("Connection没有打开或者已经被关闭"));
}
public SqlCommand CreateCommand(string commandText)
{
if(commandText==null)
throw(new ArgumentNullException("commandText"));
CheckConnection();
return new SqlCommand(commandText,conn,trans);
}
public SqlDataAdapter CreateAdapter(string commandText)
{
if(commandText==null)
throw(new ArgumentNullException("commandText"));
CheckConnection();
return new SqlDataAdapter(CreateCommand(commandText));
}
/// <summary>
/// 和Commit或Rollback对应
/// </summary>
public void BeginTransaction()
{
if(stack==null)
{
try
{
OpenConnection(true);
}
catch(Exception x)
{
Dispose();
throw(x);
}
}
else
{
trans.Save("trans"+stack.Count.ToString());
}
stack.Push(true);
}
public void Commit()
{
CheckConnection();
bool isTrans=(bool)stack.Peek();
if(!isTrans)
throw(new SqlScopeException("不能使用Commit,因为对应的一次调用不是BeginTransaction"));
stack.Pop();
if(stack.Count==0)
{
try
{
trans.Commit();
}
finally
{
Dispose();
}
}
}
public void Rollback()
{
CheckConnection();
bool isTrans=(bool)stack.Peek();
if(!isTrans)
throw(new SqlScopeException("不能使用Rollback,因为对应的一次调用不是BeginTransaction"));
stack.Pop();
if(stack.Count==0)
{
trans.Rollback("trans");
Dispose();
}
else
{
trans.Rollback("trans"+stack.Count.ToString());
}
} /// <summary>
/// 和EnterQuery对应,和BeginTransaction不同之处,是它不会启动Transaction
/// </summary>
public void EnterQuery()
{
if(stack==null)
{
OpenConnection(false);
}
stack.Push(false);
}
public void LeaveQuery()
{
CheckConnection();
bool isTrans=(bool)stack.Peek();
if(isTrans)
throw(new SqlScopeException("不能使用LeaveQuery,因为对应的一次调用不是EnterQuery"));
stack.Pop();
if(stack.Count==0)
{
Dispose();
}
}
}
}

解决方案 »

  1.   

    //by lostinet.com
    using System;
    using System.Data;
    using System.Data.SqlClient;namespace ct
    {
    class Class1
    {
    static string ConnectionString
    {
    get
    {
    return "server=(local);trusted_connection=true;database=northwind;";
    }
    } static void BuildTable()
    {
    using(SqlScope ss=new SqlScope(ConnectionString))
    {
    ss.BeginTransaction();
    using(SqlCommand cmd=ss.CreateCommand(
      @"
    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[test]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
    drop table [dbo].[test]CREATE TABLE [dbo].[test] (
    [id] [int] IDENTITY (1, 1) NOT NULL ,
    [text] [nvarchar] (1000) COLLATE Chinese_PRC_CI_AS NOT NULL 
    ) ON [PRIMARY]ALTER TABLE [dbo].[test] WITH NOCHECK ADD 
    CONSTRAINT [PK_test] PRIMARY KEY  CLUSTERED 
    (
    [id]
    )  ON [PRIMARY] 
    "
      ))
    {
    cmd.ExecuteNonQuery();
    } ss.Commit(); //并不需要使用Rollback,因为SqlScope是在这里被创建的。
    //如果ss没有被提交,最后Dispose时会自动Rollback
    }
    }
    static int InsertText(SqlScope ss,string text)
    {
    using(SqlCommand cmd=ss.CreateCommand(
      @"
    SET NOCOUNT ON
    INSERT INTO test(text) VALUES(@text)
    SET NOCOUNT OFF
    SELECT SCOPE_IDENTITY();
    "
      ))
    {
    cmd.Parameters.Add("@text",SqlDbType.NVarChar,1000).Value=text;
    return Convert.ToInt32(cmd.ExecuteScalar());
    }
    }
    [STAThread]
    static void Main(string[] args)
    {
    BuildTable(); Console.WriteLine("开始ExecuteA");
    ExecuteA("Call ExecuteA In Main");
    Console.WriteLine();
    using(SqlScope ss=new SqlScope(ConnectionString))
    {
    ss.BeginTransaction(); //以下的调用是共用一个Connection和Transaction try
    {
    Console.WriteLine();
    Console.WriteLine("开始ExecuteB");
    ExecuteB(ss);
    }
    catch
    {
    }
    try
    {
    Console.WriteLine();
    Console.WriteLine("开始ExecuteC");
    ExecuteC(ss);
    }
    catch
    {
    }
    try
    {
    Console.WriteLine();
    Console.WriteLine("开始ExecuteD");
    ExecuteD(ss);
    }
    catch
    {
    } ss.Commit();
    } using(SqlScope ss=new SqlScope(ConnectionString))
    {
    //ss在这里并没有调用BeginTransaction
    //在ExecuteD里,不会产生事务。
    try
    {
    Console.WriteLine();
    Console.WriteLine("最后一次调用ExecuteD");
    ExecuteD(ss);
    }
    catch
    {
    }
    }
    } static void ExecuteA(string msg)
    {
    SqlScope ss=new SqlScope(ConnectionString);
    ss.BeginTransaction();
    try
    { int msgid=InsertText(ss,msg);
    Console.WriteLine("A msgid={0} OK",msgid); ExecuteB(ss); try
    {
    ExecuteC(ss);
    ExecuteD(ss);
    }
    catch
    {
    //忽略C,D的异常。
    } //到这里提交结果。
    ss.Commit();
    }
    catch(Exception x)
    {
    ss.Rollback(); Console.WriteLine("A异常 : "+x.Message);
    throw(x);
    }
    } static void ExecuteB(SqlScope ss)
    {
    ss.BeginTransaction();
    try
    { int msgid=InsertText(ss,null);//异常。text不能为NULL
    Console.WriteLine("B msgid={0} OK",msgid); ExecuteC(ss);
    ExecuteD(ss); ss.Commit();
    }
    catch(Exception x)
    {
    //异常后回滚 B 的操作,但是不影响调用 B 的外部程序。例如 Main 或 A
    ss.Rollback(); Console.WriteLine("B异常 : "+x.Message);
    }
    }
    static void ExecuteC(SqlScope ss)
    {
    ss.BeginTransaction();
    try
    {
    int msgid=InsertText(ss,"ExecuteC..");
    Console.WriteLine("C msgid={0} OK",msgid);
    //可以见到有C msgid={0} OK的输出。
    //但是因为下面D抛出了异常。所以后面的Rollback被调用了 ExecuteD(ss); ss.Commit();
    }
    catch(Exception x)
    {
    ss.Rollback(); Console.WriteLine("C异常 : "+x.Message);
    }
    }
    static void ExecuteD(SqlScope ss)
    {
    ss.EnterQuery();
    //try,finally是必须的。
    //必须保证调用了EnterQuery后能调用LeaveQuery try
    {
    DataSet ds=new DataSet(); using(SqlDataAdapter sda=ss.CreateAdapter("SELECT * FROM test WHERE id=2003"))
    {
    sda.Fill(ds);
    string text=ds.Tables[0].Rows[0]["text"].ToString();//异常。Rows.Count为0
    Console.WriteLine("D getmsg:{0}",text);
    } }
    catch(Exception x)
    {
    Console.WriteLine("D异常 : "+x.Message);
    throw(x);
    }
    finally
    {
    ss.LeaveQuery();
    }
    }
    }
    }
      

  2.   

    主题已经迁移到:http://expert.csdn.net/Expert/TopicView1.asp?id=1629325