トップ回答者
トランザクションを利用したプレビュー機能

質問
-
ある特定のテーブルの内容を表示する画面が既に作成済みとなっております。
そのテーブルを編集する画面もほぼ完成しております。
編集画面の内容を一時的表示確認したい場合にトランザクションを用居れば簡単ではないのかと想像して、
表示用の画面で使用している SqlDataSource の Selecting イベントに insert 文を発行する様に記述して、
Selected イベントで Selecting イベントで使用したSQLのコネクションなどの解放処理を入れてます。
サンプルコードを作って試しに動かしたところ、タイムアウトエラーになってしまいます。
やはり同じコネクションオブジェクトじゃないと、一時的な書き込み中に表示するというのは出来ないのでしょうか?
また、他に良い方法などありましたら、ご教授していただけると助かります。
以上、よろしくお願いします。
----------------------------------------------------------------------------------------------------------------------------------------------------------------
サンプルで作成したコード
Preview.aspx<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Preview.aspx.cs" Inherits="Test_Preview" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>無題のページ</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataSourceID="SqlDataSource1">
<Columns>
<asp:BoundField DataField="ReferTypeNo" HeaderText="ReferTypeNo" SortExpression="ReferTypeNo" />
<asp:BoundField DataField="Description" HeaderText="Description" SortExpression="Description" />
<asp:BoundField DataField="FolderName" HeaderText="FolderName" SortExpression="FolderName" />
</Columns>
</asp:GridView>
</div>
<aspqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings
BConnectionString %>"
OnSelected="SqlDataSource1_Selected" OnSelecting="SqlDataSource1_Selecting" SelectCommand="SELECT * FROM [TestTable]">
</aspqlDataSource>
</form>
</body>
</html>Preview.aspx.csusing System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Collections;
using System.Transactions;
using System.Web;
using System.Web.Configuration;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;public partial class Test_Preview : System.Web.UI.Page
{
private const string CONNECTION = "{SQL Server2005への接続文字列}";
private SqlConnection conn = null;
private SqlCommand cmd = null;
private SqlTransaction tran = null;protected void SqlDataSource1_Selecting(object sender, SqlDataSourceSelectingEventArgs e)
{
this.Update();
}protected void SqlDataSource1_Selected(object sender, SqlDataSourceStatusEventArgs e)
{
this.Rollback();
}private string GetInsertSQL()
{
return @"
INSERT INTO TestTable
(
Column1
, Column2
, Column3
)
VALUES
(
13
, 'Transaction Test'
, 'uri'
)";
}private void Update()
{
try
{
this.conn = new SqlConnection(CONNECTION);
this.conn.Open();this.tran = conn.BeginTransaction(System.Data.IsolationLevel.ReadUncommitted);
this.cmd = new SqlCommand(this.GetInsertSQL(), this.conn, this.tran);
this.cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
try
{
this.tran.Rollback();
this.tran = null;
}
catch (SqlException ex2)
{
if (this.tran != null)
{
throw new Exception("An exception of type " + ex2.GetType() +
" was encountered while attempting to roll back the transaction.");
}
}this.conn.Close();
this.conn = null;throw ex;
}
}private void Rollback()
{
if (this.conn != null)
{
try
{
this.tran.Rollback();
}
catch (Exception ex)
{
this.tran.Rollback();
this.tran = null;throw ex;
}
finally
{
this.conn.Close();
this.conn = null;
}
}
}
}
回答
-
同一のコネクションを使うことで動くことを確認しました。
その場合 SqlDataSource は Selecting の時に無条件で 「e.Cancel = true;」 とすれば、トランザクションありの登録・更新・検索をまとめて行う関数を呼び出してバインドできると、実権により確認できました。
時間的に余裕が無いため他のテストコードを試さずに投稿してしまいました。
次からは自分が思い浮かぶ方法をすべて試してから投稿したいと思います。。
検証した関数private DataTable InsupSelect()
{
DataTable table = new DataTable();using (TransactionScope scope = new TransactionScope())
{
using (SqlConnection conn = new SqlConnection("{SQL Server 2005への接続文字列}"))
{
SqlCommand cmd = new SqlCommand(this.GetInsertSQL(), conn);
cmd.Connection.Open();try
{
cmd.ExecuteNonQuery();
}
catch (SqlException ex)
{
this.Context.Trace.Write(string.Format("SQL登録例外エラー:{0}{1}", Environment.NewLine, ex.ToString()));
}SqlDataReader reader = null;
try
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "sp_TestTable";reader = cmd.ExecuteReader();
if (reader.HasRows)
{
// 列名
if (table.Columns.Count <= 0)
{
for (int i = 0; i < reader.FieldCount; i++)
{
table.Columns.Add(new DataColumn(reader.GetName(i), reader.GetFieldType(i)));
}
}// 行
while (reader.Read())
{
object[] rows = new object[reader.FieldCount];
for (int i = 0; i < reader.FieldCount; i++)
{
rows[i] = reader[i];
}table.Rows.Add(rows);
}
}
}
catch (SqlException ex)
{
this.Context.Trace.Write(string.Format("SQL検索例外エラー:{0}{1}", Environment.NewLine, ex.ToString()));
}
finally
{
reader.Close();
reader.Dispose();
reader = null;
}
}//// 以下のコードはあえて実行しないことによりロールバックを想定しています。
// scope.Complete();
}return table;
}
すべての返信
-
同一のコネクションを使うことで動くことを確認しました。
その場合 SqlDataSource は Selecting の時に無条件で 「e.Cancel = true;」 とすれば、トランザクションありの登録・更新・検索をまとめて行う関数を呼び出してバインドできると、実権により確認できました。
時間的に余裕が無いため他のテストコードを試さずに投稿してしまいました。
次からは自分が思い浮かぶ方法をすべて試してから投稿したいと思います。。
検証した関数private DataTable InsupSelect()
{
DataTable table = new DataTable();using (TransactionScope scope = new TransactionScope())
{
using (SqlConnection conn = new SqlConnection("{SQL Server 2005への接続文字列}"))
{
SqlCommand cmd = new SqlCommand(this.GetInsertSQL(), conn);
cmd.Connection.Open();try
{
cmd.ExecuteNonQuery();
}
catch (SqlException ex)
{
this.Context.Trace.Write(string.Format("SQL登録例外エラー:{0}{1}", Environment.NewLine, ex.ToString()));
}SqlDataReader reader = null;
try
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "sp_TestTable";reader = cmd.ExecuteReader();
if (reader.HasRows)
{
// 列名
if (table.Columns.Count <= 0)
{
for (int i = 0; i < reader.FieldCount; i++)
{
table.Columns.Add(new DataColumn(reader.GetName(i), reader.GetFieldType(i)));
}
}// 行
while (reader.Read())
{
object[] rows = new object[reader.FieldCount];
for (int i = 0; i < reader.FieldCount; i++)
{
rows[i] = reader[i];
}table.Rows.Add(rows);
}
}
}
catch (SqlException ex)
{
this.Context.Trace.Write(string.Format("SQL検索例外エラー:{0}{1}", Environment.NewLine, ex.ToString()));
}
finally
{
reader.Close();
reader.Dispose();
reader = null;
}
}//// 以下のコードはあえて実行しないことによりロールバックを想定しています。
// scope.Complete();
}return table;
} -
同一のコネクションを使うことで動くことを確認しました。
その場合 SqlDataSource は Selecting の時に無条件で 「e.Cancel = true;」 とすれば、トランザクションありの登録・更新・検索をまとめて行う関数を呼び出してバインドできると、実権により確認できました。
時間的に余裕が無いため他のテストコードを試さずに投稿してしまいました。
次からは自分が思い浮かぶ方法をすべて試してから投稿したいと思います。。
検証した関数private DataTable InsupSelect()
{
DataTable table = new DataTable();using (TransactionScope scope = new TransactionScope())
{
using (SqlConnection conn = new SqlConnection("{SQL Server 2005への接続文字列}"))
{
SqlCommand cmd = new SqlCommand(this.GetInsertSQL(), conn);
cmd.Connection.Open();try
{
cmd.ExecuteNonQuery();
}
catch (SqlException ex)
{
this.Context.Trace.Write(string.Format("SQL登録例外エラー:{0}{1}", Environment.NewLine, ex.ToString()));
}SqlDataReader reader = null;
try
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "sp_TestTable";reader = cmd.ExecuteReader();
if (reader.HasRows)
{
// 列名
if (table.Columns.Count <= 0)
{
for (int i = 0; i < reader.FieldCount; i++)
{
table.Columns.Add(new DataColumn(reader.GetName(i), reader.GetFieldType(i)));
}
}// 行
while (reader.Read())
{
object[] rows = new object[reader.FieldCount];
for (int i = 0; i < reader.FieldCount; i++)
{
rows[i] = reader[i];
}table.Rows.Add(rows);
}
}
}
catch (SqlException ex)
{
this.Context.Trace.Write(string.Format("SQL検索例外エラー:{0}{1}", Environment.NewLine, ex.ToString()));
}
finally
{
reader.Close();
reader.Dispose();
reader = null;
}
}//// 以下のコードはあえて実行しないことによりロールバックを想定しています。
// scope.Complete();
}return table;
}