 |
|
 |
I came across your code and I was in the middle of implementing your code.
But for shared transaction, the rollback was not initiated fully
/// xta.BeginTransation(); /// yta.Transation = xta.Transaction; /// try /// { /// // perform xta and yta modifications here. /// xta.CommitTransaction(); /// } /// catch( Exception ) /// { /// xta.RollbackTransaction(); /// }
In this eg: only rollback works for xta. How can I have the rollback for yta ?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
I found this works fine in VB.NET 2005. Although if you edit the dataset in the designer, the reference to BizWiz gets decorated to Global.BizWiz which breaks the compiler.
' ---------------------------------------------------------------------------- ' ' TransactionSupport ' ' Original author: Mike Pagel ' After ideas given in ' http:'www.codeproject.com/useritems/typed_dataset_transaction.asp ' http:'entwickler-forum.de/showpost.php?p=2032&postcount=2 ' ' Translated to VB and converted to OLEDB for use with MS ACCESS (Jet) by Jim Hansen, Jan 2009 ' ----------------------------------------------------------------------------
'imports System.Data.SqlClient Imports System.Data.OleDb imports System.Data imports System.Reflection
namespace BizWiz
'/ '/ Transaction support for generated table adapters. '/ '/ '/ me class adds transaction support to table adapters. It is used by changing the base '/ class of a table adapter from Component to me class. The implementation of me class '/ then accesses the derived table adapter's properties through reflection. '/ Public MustInherit Class TransactionSupport Inherits System.ComponentModel.Component
' -------------------------------------------------------------------- #Region "Reflective access to table adapter properties" ' -------------------------------------------------------------------- Private Property Connection() As OleDbConnection 'SqlConnection
' Access to propertis as public and non-public as generated table-adapter ' scope seems to be different for different installations: ' http:'www.codeproject.com/useritems/transactionta.asp?msg=2225021#xx2225021xx Get 'return (SqlConnection)GetType().GetProperty( "Connection", BindingFlags.Public or BindingFlags.NonPublic or BindingFlags.Instance ).GetValue( me, nothing ) Return Me.GetType().GetProperty("Connection", BindingFlags.Public Or BindingFlags.NonPublic Or BindingFlags.Instance).GetValue(Me, Nothing) End Get Set(ByVal value As OleDbConnection) ' SqlConnection) Me.GetType().GetProperty("Connection", BindingFlags.Public Or BindingFlags.NonPublic Or BindingFlags.Instance).SetValue(Me, value, Nothing) End Set End Property
' -------------------------------------------------------------------- Private ReadOnly Property Adapter() As OleDbDataAdapter 'SqlDataAdapter
Get
Return Me.GetType().GetProperty("Adapter", BindingFlags.NonPublic Or BindingFlags.Instance).GetValue(Me, Nothing) End Get End Property
' -------------------------------------------------------------------- Private ReadOnly Property CommandCollection() As OleDbCommand() 'SqlCommand()
Get
Return Me.GetType().GetProperty("CommandCollection", BindingFlags.NonPublic Or BindingFlags.Instance).GetValue(Me, Nothing) End Get End Property
#End Region ' -------------------------------------------------------------------- #Region "Properties" ' -------------------------------------------------------------------- '/ '/ Transaction of me table adapter. '/ '/ '/ me property is used to share a transaction and its associated connection '/ across multiple table adapters. The typical pattern is shown in the sample '/ code below. '/ '/ '/ XTableAdapter xta = new XTableAdapter() '/ YTableAdapter yta = new YTableAdapter() '/ '/ xta.BeginTransation() '/ yta.Transation = xta.Transaction '/ try '/ { '/ ' perform xta and yta modifications here. '/ xta.CommitTransaction() '/ } '/ catch( Exception ) '/ { '/ xta.RollbackTransaction() '/ } '/ Public Property Transaction() As OleDbTransaction 'SqlTransaction
Get Return my_transaction End Get Set(ByVal value As OleDbTransaction) ' SqlTransaction)
' attach transaction to all commands of my adapter: If CommandCollection IsNot Nothing Then For Each command As OleDbCommand In CommandCollection 'SqlCommand In CommandCollection command.Transaction = value Next 'command End If If Adapter.InsertCommand IsNot Nothing Then Adapter.InsertCommand.Transaction = value End If If Adapter.UpdateCommand IsNot Nothing Then Adapter.UpdateCommand.Transaction = value End If If Adapter.DeleteCommand IsNot Nothing Then Adapter.DeleteCommand.Transaction = value End If
' also set connection of my adapter accordingly: If value IsNot Nothing Then Connection = value.Connection Else
' only clear connection if it was attached to ' transaction before: If (Transaction IsNot Nothing) Then Connection = Nothing End If End If
my_transaction = value End Set End Property
#End Region ' -------------------------------------------------------------------- #Region "Operations" ' -------------------------------------------------------------------- Public Sub BeginTransaction()
' Open the connection, if needed If (Connection.State <> ConnectionState.Open) Then Connection.Open() End If ' Create the transaction and assign it to the Transaction property Transaction = Connection.BeginTransaction() End Sub
' -------------------------------------------------------------------- Public Sub CommitTransaction()
' Commit the transaction my_transaction.Commit()
' Close the connection Connection.Close() End Sub
' -------------------------------------------------------------------- Public Sub RollbackTransaction()
' Rollback the transaction my_transaction.Rollback()
' Close the connection Connection.Close() End Sub
#End Region ' -------------------------------------------------------------------- #Region "Fields" ' -------------------------------------------------------------------- '/ '/ Fields supporting properties. '/ Private my_transaction As OleDbTransaction 'SqlTransaction
#End Region ' --------------------------------------------------------------------
End Class end namespace
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
whenever i share an open connection with multiple TableAdapters the TM stays LTM and won't get promoted to MSDTC. i'm using VS 2k8 with .net 3.5 + SQL 2k5 and can't really reproduce the behavior mentioned in the first passage, that is, i'm using multiple TableAdapters within a TransactionScopes without having my TM escalated. any thoughts on that? probably something MS changed between the .net versions?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
What you put:
// begin transaction and share it among all participating table-adapters: customerTableAdapter.BeginTransaction(); orderTableAdapter.Transaction = customerTableAdapter.Transaction;
// now start the modifications: try { WHAT GOES IN HERE??? customerTableAdapter.Insert("blob"); <----------- it still inserts
// ok, all is well, commit transaction: customerTableAdapter.CommitTransaction(); } catch( Exception e ) { // if anything went wrong, roll-back transaction customerTableAdapter.RollbackTransaction(); }
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
The Transaction used in the Topic is the Transaction property of TableAdapter. No the property of TransactionSupport
The handle this, i think we can rename the Transaction get setter in TransactionSupport.cs such as 'SharedTransaction'
Finally , we can: orderTableAdapter.SharedTransaction=customerTableAdapter.SharedTransaction
Tim
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I am using MySQLConnector.Net 5.2.1, SQLYog CommunityEdition v6.16, VS 2005 (C#).
I have created several table adapters using XSD Wizard and I am not using insertcommand, updatecommand, selectcommand and deletecommand. I have just created a delete SQL text through the XSD wizard for the table adapters.
However, I used your transactionsupport class and I still cannot get it to work and it still deletes and never does a rollback.
Do you have any ideas or suggestions on how the coding in C# should be done to make the rollback occur for MySql Database?
I would appreciate your help as I am struggling to find an answer to this.
Thanks
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi,
I have no experience with the connectors you mention. However, the transaction used in my class is attached to all default commands of the table adapter. I suspect that this does not happen for your literal SQL statement.
Take a look at the TransactionSupport.Transaction property. Its setter is currently implemented as:
public SqlTransaction Transaction { set { if( CommandCollection != null ) { foreach( SqlCommand command in CommandCollection ) { command.Transaction = value; } } if( Adapter.InsertCommand != null ) { Adapter.InsertCommand.Transaction = value; } if( Adapter.UpdateCommand != null ) { Adapter.UpdateCommand.Transaction = value; } if( Adapter.DeleteCommand != null ) { Adapter.DeleteCommand.Transaction = value; } ... } }
Put a breakpoint in there. Is your custom command also modified by setting its Transaction property?
If you find out what's going on, please let me know. I am happy to update the base class.
Mike
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi
I am not sure what you mean by:
"Is your custom command also modified by setting its Transaction property?"
Can you please explain?
Thanks
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Many thanks for providing this class. I added it in my project & changed the base class for my tableadapters & it all works like a charm. The other solutions would have required me to enable network access to DTC/enable the MSDTC service on the server, but the solution you posted avoided all that & still works fine. Thanks again 
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
First, thanks for the code. I was not looking forward to the copy/pasting the transaction property for 40 different adapters in my project. This really helped me out 
Second, I believe the problem with the scope on the connection object (thread here) has to do with how the adapter is set up. In the designer, if you check the properties on an adapter, you can change the scope of the connection by changing the "ConnectionModifier". My guess would be that the person in the thread below here had his defined as public, while the author had his defined as internal, protected, or private.
Regardless, the fix to make the code work for everybody is to change the binding flags on the reflection as the author did. Nice work, and thanks again.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
if you want to implement transaction with strongly typed dataset it is some what trikey,
Table adapters which are created in typed datasets are implemented in partial classes by visual studio 2005,
if you want to use multiple table adapters in one transaction than you have to follow this sceanario.....
implement partial classes foR all your table adapters like this use onky one connection object for all, (assign new connection to first adapter and to other pass just reference of that connection)
Partial classes are used to extend the functionality provided by TableAdapters. They are to be written in “App_Code” folder. In partial classes, the physical files are scattered any where in the project with the same name like “public partial class ” but when project is compiled all the physical files are combined like one physical file and make the whole class
Example of a partial class
using System; using System.Data; using System.Data.SqlClient; namespace dsGroundSelectTableAdapters { public partial class ADAPTERNAME_TableAdapter { private SqlTransaction _transaction; private SqlTransaction Transaction { get { return this._transaction; } set { this._transaction = value; } } public SqlConnection GetConnection() { return this.Connection; } public void SetConnection(ref SqlConnection Conn) { this.Connection = Conn; } public SqlTransaction GetTransaction() { return this.Transaction; } public void SetTransaction(ref SqlTransaction Trans) { this.Transaction = Trans; foreach (SqlCommand command in this.CommandCollection) { command.Transaction = this.Transaction; } this.Adapter.InsertCommand.Transaction = this.Transaction; } public void BeginTransaction() { // Open the connection, if needed if (this.Connection.State != ConnectionState.Open) { this.Connection.Open(); } // Create the transaction and assign it to the Transaction property this.Transaction = this.Connection.BeginTransaction(); // Attach the transaction to the Adapters foreach (SqlCommand command in this.CommandCollection) { command.Transaction = this.Transaction; } this.Adapter.InsertCommand.Transaction = this.Transaction; } public void CommitTransaction() { // Commit the transaction this.Transaction.Commit(); // Close the connection this.Connection.Close(); } public void RollbackTransaction() { // Rollback the transaction this.Transaction.Rollback(); // Close the connection this.Connection.Close(); } }}
************************ and in code behind file
//////create object of all your adapters
(1) dsDATASETNAMETableAdapters.ADAPTERNAMETableAdapter daOBJECT1 = new dsDATASETNAMETableAdapters.ADAPTERNAMETableAdapter();
(2) dsDATASETNAMETableAdapters.ADAPTERNAMETableAdapter daOBJECT2 = new dsDATASETNAMETableAdapters.ADAPTERNAMETableAdapter();
(3) dsDATASETNAMETableAdapters.ADAPTERNAMETableAdapter daOBJECTn = new dsDATASETNAMETableAdapters.ADAPTERNAMETableAdapter();
/////////create connection ///////// assign it to first adapter object and give others a refernce ////////to the same
/////////all operation must be performed using first adapter object
//even they all are refernced by a same connectin they all are in one ///////transaction...
SqlConnection Conn= new SqlConnection(); Conn=daOBJECT1.GetConnection(); daOBJECT2.SetConnection(ref Conn); daOBJECTn.SetConnection(ref Conn);
daOBJECT1.BeginTransaction();
SqlTransaction trnTrans = daOBJECT1.GetTransaction(); daOBJECT2.SetTransaction(ref trnTmpTrans); daOBJECTn.SetTransaction(ref trnTmpTrans); try { //EXECUTE YOUR QUERIES HERE // YOU CAN CALL FUNCTIONS TO UPDATE INSERT DATA //insertDATAInTable(); //updateDATATable();
daOBJECT1.CommitTransaction(); } catch (Exception ex) { daOBJECT1.RollbackTransaction(); }
*********************************** Anil Pandya Senior Software Programmer Mumbai +919920066603
anil
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Thanks for the comment, but I am not quite sure what you want to say... Do you have an issue with my implementation that you suggest to solve in a specific way?
Mike
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
 |
i was having problem with transaction... but i found a solutions in proper way and implemented with my whole project. so i have just described it to public
Anil Pandya Programmer Mumbai- India
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
 |
In order for this to work for me, I had to change the NonPublic BindingFlags to Public in the Connection property Set & Get.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I am wondering why it behaves differently on your machine... You said you changed it from NonPublic to Public. I remember that did not work for me, though.
Could you try combining the two as in NonPublic | Public (or did you actually already do it that way)? That should work for both of us. If you could post quick feedback I will upload a modified version afterwards.
Thanks a lot, Mike
-- modified at 2:36 Thursday 13th September, 2007
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
For some reason my Connection property is public in my table adapters outside the BaseClass. I did create my DataTable and Adapters within an XSD DataSet via the Toolbox wizard.
The combination of the two BindingFlags worked as expected.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Thanks. I uploaded an updated version. Just setting it to public still does not work for me. Connection is internal for my table adapters...
Mike
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Who's to say that the non-public property you used will still be there in the next version of the framework?! Or that it will have the same meaning?
Reflection enables you to access everything, but remember the price - possible version incompatability.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I am aware of the risk involved in accessing properties this way. However, after comparing the different approaches possible the one chosen seemed the most elegant. As I said in the article, there are other solutions out suggesting to use partial classes, which is suffering from the same issues.
At least, after an update to an incompatible framework version, you must adapt one central class only.
Please let me know if you are aware of a better way going through public members only.
Mike
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I am using the "partial classes" solution for few months and I was very flustrated by the amout of code, which I must to write again and again. For EVERY table adapter I must wrote property Transaction, Connection etc, approx 100 lines of code. Thanks to this article I wrote my table adapters very fast now Reflection is good idea in this case.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Thanks for great idea!
I am thining about performance of your reflection-based properties. I think it would be betted to cache values after getting by reflection, see bellow.
if (_savedCommand == null) { _savedCommand = (SqlCommand[])GetType().GetProperty( "CommandCollection", BindingFlags.NonPublic | BindingFlags.Instance ).GetValue( this, null ); } return _savedCommand;
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
 |
Hey Karel,
you have a valid point there, as this is the typical trade-off between memory footprint and runtime, both of which are performance values though.
However, there is one more relevant backdraw in implementing cache members for the three properties that is an issue with all cache implementations: you have to know about when the cache becomes invalid. As I did not want to bother with studying when and how those members of the tableadapters are (re-)initialized I took the safe route.
Also it simply felt wrong to introduce cache variables that directly copy existing variables in the derived table-adapter.
Finally, I am not sure how big of a deal the runtime overhead actually is. Did you hit a scalability issue? I am wondering what kind of usage pattern would create problems here.
Thanks, Mike
|
| Sign In·View Thread·PermaLink | 1.71/5 (3 votes) |
|
|
|
 |