#眉標=TxF、P/Invoke、AlphaFS #副標=交易式的檔案處理(2) #大標=結合檔案及資料庫的交易處理 #作者=文/圖 吳剛志 ================= 程式1 string connstr = ConfigurationManager.ConnectionStrings["photoDB"].ConnectionString; using (SqlConnection conn = new SqlConnection(connstr)) { conn.Open(); SqlCommand cmd = conn.CreateCommand(); cmd.CommandText = @" insert photos (Description, ImagePath) values (@desc, @path); select NULLIF(SCOPE_IDENTITY(), 0);"; foreach (UploadPhotoData p in this.GetUploadPhotos()) { string path = string.Format( "{0:N}.jpg", Guid.NewGuid()); p.FileUploadControl.SaveAs( this.Server.MapPath("~/App_Data/photos/" + path)); this.Trace.Write( string.Format("檔案({0}) 上傳成功", path)); cmd.Parameters.Clear(); cmd.Parameters.AddWithValue( "desc", p.TextBoxControl.Text); cmd.Parameters.AddWithValue("path", path); int resultPK = (int)(decimal)cmd.ExecuteScalar(); this.Trace.Write(string.Format( "資料庫 [photos.PK: {0}] 更新成功", resultPK)); } } ================ ================ 程式2 //用TransactionScope標示交易範圍 using (TransactionScope scope = new TransactionScope()) { //更新檔案 //更新資料庫 // throw new Exception("cancel transaction"); //認可scope範圍內的交易 scope.Complete(); } ================ ================ 程式3 SafeFileHandle fh = CreateFileTransacted( this.Server.MapPath("~/App_Data/photos/" + path), 0x40000000, 0x00000000, IntPtr.Zero, 0x00000001, 0x00000080, IntPtr.Zero, kth, IntPtr.Zero, IntPtr.Zero); Stream source = p.FileUploadControl.PostedFile.InputStream; Stream target = new FileStream(fh, FileAccess.Write); byte[] buffer = new byte[4096]; int count = 0; while ((count = source.Read(buffer, 0, buffer.Length)) > 0) { target.Write(buffer, 0, count); } source.Close(); target.Close(); this.Trace.Write(string.Format( "檔案({0})上傳成功", path)); ================ ============= 程式4 IDtcTransaction dtc = TransactionInterop.GetDtcTransaction( Transaction.Current); IKernelTransaction ktm = (IKernelTransaction)dtc; IntPtr kth; ktm.GetHandle(out kth); ================ ============= 程式5 using (TransactionScope scope = new TransactionScope()) { try { //準備交易物件Handle: kth IDtcTransaction dtc = TransactionInterop.GetDtcTransaction( Transaction.Current); IKernelTransaction ktm = (IKernelTransaction)dtc; IntPtr kth; ktm.GetHandle(out kth); using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["photoDB"].ConnectionString)) { conn.Open(); SqlCommand cmd = conn.CreateCommand(); cmd.CommandText = @" insert photos (Description, ImagePath) values (@desc, @path); select NULLIF(SCOPE_IDENTITY(), 0);"; foreach (UploadPhotoData p in this.GetUploadPhotos()) string path = string.Format( "{0:N}.jpg", Guid.NewGuid()); // 取得檔案的 Handle SafeFileHandle fh = CreateFileTransacted( this.Server.MapPath( "~/App_Data/photos/" + path), 0x40000000, 0x00000000, IntPtr.Zero, 0x00000001, 0x00000080, IntPtr.Zero, kth, IntPtr.Zero, IntPtr.Zero); Stream source = p.FileUploadControl.PostedFile.InputStream; Stream target = new FileStream(fh, FileAccess.Write); // 複製 Stream byte[] buffer = new byte[4096]; int count = 0; while ((count = source.Read(buffer, 0, buffer.Length)) > 0) { target.Write(buffer, 0, count); } source.Close(); target.Close(); this.Trace.Write(string.Format( "檔案 ({0}) 上傳成功", path)); // 寫入資料庫 cmd.Parameters.Clear(); cmd.Parameters.AddWithValue( "desc", p.TextBoxControl.Text); cmd.Parameters.AddWithValue( "path", path); int resultPK = (int)(decimal)cmd.ExecuteScalar(); this.Trace.Write(string.Format( "資料庫 [photos.PK: {0}] 更新成功", resultPK)); } } //throw new Exception("cancel transaction"); scope.Complete(); } catch (Exception ex) { this.Trace.Warn("Exception", ex.ToString()); this.Trace.Warn("Transaction Rollback."); throw; } } ================ ================= 程式6 using (TransactionScope scope = new TransactionScope()) { try { //透過Ambient Transaction,取得KernelTransaction物件 KernelTransaction ktm = new KernelTransaction(Transaction.Current); using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["photoDB"].ConnectionString)) { //開啟資料庫連線,及準備SqlCommand物件,略 foreach (UploadPhotoData p in this.GetUploadPhotos()) { string path = string.Format( "{0:N}.jpg", Guid.NewGuid()); Stream source = p.FileUploadControl.PostedFile.InputStream; //以支援交易的方式開啟檔案 Stream target = File.Open( ktm, this.Server.MapPath("~/App_Data/photos/" + path), FileMode.Create, FileAccess.Write); //複製Stream,略 this.Trace.Write(string.Format( "檔案{0}上傳成功", path)); //寫入資料庫,略 } } throw new Exception("cancel transaction"); scope.Complete(); } catch (Exception ex) { this.Trace.Warn("Exception", ex.ToString()); this.Trace.Warn("Transaction Rollback."); throw; } } ================ 本文的完整範例程式,可至www.runpc.com.tw,或是筆者部落格:columns.chicken-house.net/category/RUNPC.aspx上下載。