I've got a integration test that looks like this:
using (var tran = Connection.BeginTransaction(IsolationLevel.ReadUncommitted))
{
try
{
// Act.
var result = controller.Create(something);
// Assert.
Assert.IsNotNull(result);
}
catch (Exception exc)
{
Assert.Fail(exc.Message);
}
finally
{
tran.Rollback();
Connection.Close();
}
}
Now, in that Create method, i end up calling a stored procedure which returns multiple result sets.
Here's the code to call that SP:
var cmd = Database.Connection.CreateCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "exec dbo.MySP #SomeParam";
cmd.Parameters.Add(new SqlParameter { Value = "test", ParameterName = "SomeParam" });
using (var rdr = cmd.ExecuteReader()) <--- exception thrown here.
{
// code to read result sets.
}
I get the following exception:
System.InvalidOperationException: ExecuteReader requires the command to have a transaction when the connection assigned to the command is in a pending local transaction. The Transaction property of the command has not been initialized.
Which i guess makes sense, but i would have thought it would inherit the pending local transaction?
I previously had the above code open a new connection, but it just timed out due to an apparent lock the pending transaction had on certain tables, despite the read uncommitted isolation level.
Basically, i need to be able to have an integration test which:
Opens a transaction
Does some stuff, including saving some records to the db, then calling another stored procedure which accesses data which includes the newly created data
Rollback the transaction.
Any ideas guys?
This works:
using (new TransactionScope(TransactionScopeOption.Required,
new TransactionOptions
{
IsolationLevel = IsolationLevel.ReadUncommitted
}))
This doesn't:
using (var tran = Connection.BeginTransaction(IsolationLevel.ReadUncommitted))
{
Must have something to do with the fact that TransactionScope lives outside of the actual Connection, so it wraps all connections that are opened inside of it, whilst the former code opens the transaction with a specific connection.
Related
I'm building database by using mysql connector with EF6.
Way to handling concurrency updates happens.
Client A updates row
Client B come in updates same row
Client B need to wait Client A commit his updates.
Codes:
using (myEntities db = new myEntities ())
{
db.Database.Connection.Open();
try
{
using (var scope = db .Database.BeginTransaction(System.Data.IsolationLevel.Serializable))
{
{
var test = db.customer_table.Where(x => x.id == 38).FirstOrDefault();
test.bank_holder_name = "CLIENT A";
db.SaveChanges();
scope.Commit();
}
}
}
catch (Exception ex)
{
throw;
}
}
While debugging, I purposely pause when Client A doing this SaveChanges() step.
But Client B can finish his updates without any wait.
Anyone here is experiencing this issue?
P/S: I did a lot reading and trial about Entity Framework concurrency issue, like;
a) Optimistic locking with row_version (Not working perfectly if the timestamp not unique enough to catch concurrency)
b) Transaction Scope (Still the same as result above)
Anyone here have idea to stop concurrency in Entity Framework? Thanks in Advance!
I am fighting with stored procedure with referenced linkedserver. Linked server is accesible over internet via port forwarding - so no VPN, LAN.
Servers are on both sides MS SQL SERVER 2008 EE v. 10.0.5512
Configurations Linked server, DTC:
cannot insert images yet:(
enable promotion of distributed transaction = false
RPC = false
RPC out = false
Network DTC Access checked
Allow inbound true
Allow outbound true
No authentication Required
Stored procedure looks like
CREATE PROCEDURE [dbo].[spSynchronizeArticles]
-- Add the parameters for the stored procedure here
(
#pDebug bit,
#siteId bigint
)
AS
BEGIN
SELECT *
FROM [LinkedServer].[MyDatabase].dbo.Storages
WHERE Storage.siteId = #siteId
RETURN 0
END
As you can see no transaction here. If I am correct the MS DTC is creating transaction every time when the linked server is called.
I am calling this procedure from c# like this
SqlCommand sqlCmd = new SqlCommand("spSynchronizeArticles");
sqlCmd.CommandType = CommandType.StoredProcedure;
sqlCmd.Parameters.AddWithValue("#pDebug", false);
sqlCmd.Parameters.AddWithValue("#siteId", siteId);
SqlParameter returnValue = new SqlParameter("returnVal", SqlDbType.Int);
returnValue.Direction = ParameterDirection.ReturnValue;
sqlCmd.Parameters.Add(returnValue);
using (SqlConnection conn = new SqlConnection(Context.LocalData.ConnectionString))
{
try
{
try
{
conn.Open();
sqlCmd.Connection = conn;
sqlCmd.ExecuteScalar();
return Convert.ToInt32(returnValue.Value);
}
catch (Exception ex)
{
//log exception to file
return -1;
}
}
finally
{
conn.Close();
}
}
}
This c# code is called in infinite while to synchronize data. In same Thread and while there is also another method called which is getting data from file (if any exist) and saving them to local DB.
The SynchronizeArticles method is invoking more often and everything is working, but once the method for getting data from file is called, the SynchronizeArticles always throw this exception
System.Data.SqlClient.SqlException (0x80131904): MSDTC on server
'LocalServer\SQLEXPRESS2008' is unavailable.
The method is using Transaction and looks like
public void FillDataFromViewWithTrans(DataTable dt, string wherePhrase)
{
dt.Rows.Clear();
SqlCommand sql = new SqlCommand(String.Format(#"SELECT *
FROM SomeView
{0}", String.IsNullOrEmpty(wherePhrase) ? String.Empty : "WHERE " + wherePhrase));
using (SqlConnection conn = new SqlConnection(Context.LocalData.ConnectionString))
{
SqlTransaction trans = null;
try
{
try
{
conn.Open();
trans = conn.BeginTransaction(IsolationLevel.RepeatableRead);
sql.Transaction = trans;
sql.Connection = conn;
SqlDataAdapter dA = new SqlDataAdapter(sql);
dA.Fill(dt);
trans.Commit();
}
catch (Exception ex)
{
trans.Rollback();
//log exception to file
return;
}
}
finally
{
conn.Close();
}
}
}
This is just illustration samples :)
Tell me what I am missing.
Additionally I have big troubles with the MS DTC with various errors
From C# code when some users calls the procedure manually they sometimes got exception:
The operation could not be performed because the OLE DB provider
'SQLOLEDB' was unable to begin a distributed transaction.
When I put the begin distributed transaction inside the stored procedure I got:
Warning: Fatal error 8510 occurred at Apr 10 2013 9:07AM. Note the
error and time, and contact your system administrator.
What only helps is the restart of the windows service or the UI application. From the MS SQL management studio the procedure works all the time without problems.
Now I must say I am desperate, what am I missing?
Edit:
int i = 0;
while (true)
{
i++;
if ((i % 9) == 0)
{
//local select with transaction Works all the time
CallLocalSelectWithTransaction();
}
// CallProcedure works 8 times, after first calling of CallLocalSelectWithTransaction
// the callProcedure works no more.
CallProcedure(); // procedure with linked server
}
I am trying to create a Merge Replication using RMO Programming which i got from here!
string publisherName = "DataSourceName";
string publicationName = "AdvWorksSalesOrdersMerge";
string publicationDbName = "AdventureWorksDW2008R2";
ReplicationDatabase publicationDb;
MergePublication publication;
// Create a connection to the Publisher.
ServerConnection conn = new ServerConnection(publisherName);
try
{
//Connect to the Publisher.
conn.Connect();
// Enable the database for merge publication.
publicationDb = new ReplicationDatabase(publicationDbName, conn);
if (publicationDb.LoadProperties())
{
if (!publicationDb.EnabledMergePublishing)
{
publicationDb.EnabledMergePublishing = true;
}
}
else
{
// Do something here if the database does not exist.
throw new ApplicationException(String.Format(
"The {0} database does not exist on {1}.",
publicationDb, publisherName));
}
// Set the required properties for the merge publication.
publication = new MergePublication();
publication.ConnectionContext = conn;
publication.Name = publicationName;
publication.DatabaseName = publicationDbName;
// Enable precomputed partitions.
publication.PartitionGroupsOption = PartitionGroupsOption.True;
//Specify the Windows account under which the Snapshot Agent job runs.
// This account will be used for the local connection to the
// Distributor and all agent connections that use Windows Authentication.
publication.SnapshotGenerationAgentProcessSecurity.Login = userid;
publication.SnapshotGenerationAgentProcessSecurity.Password = password;
//Explicitly set the security mode for the Publisher connection
// Windows Authentication (the default).
publication.SnapshotGenerationAgentPublisherSecurity.WindowsAuthentication = true;
//Enable Subscribers to request snapshot generation and filtering.
publication.Attributes |= PublicationAttributes.AllowSubscriberInitiatedSnapshot;
publication.Attributes |= PublicationAttributes.DynamicFilters;
// Enable pull and push subscriptions.
publication.Attributes |= PublicationAttributes.AllowPull;
publication.Attributes |= PublicationAttributes.AllowPush;
if (!publication.IsExistingObject)
{
//Create the merge publication.
publication.Create();
// Create a Snapshot Agent job for the publication.
publication.CreateSnapshotAgent();
}
else
{
throw new ApplicationException(String.Format(
"The {0} publication already exists.", publicationName));
}
}
catch (Exception ex)
{
//Implement custom application error handling here.
throw new Exception(String.Format("The publication {0} could not be created.", publicationName), ex);
}
finally
{
conn.Disconnect();
}
but at this line
publicationDb.EnabledTransPublishing = true;
i am getting error -" An exception occurred while executing a Transact-SQL statement or batch."
So please help me out from this problem ..
waiting for your answers..
You Probably have you answer by now but for those who might be asking the same question. Its because you are using an express version of SQL Server and Publisher/distributors cannot be created in any version of SQl Server Express.
The instance you have in your code there is not a valid instance hence the exception is thrown.
take a look at:
http://msdn.microsoft.com/en-us/library/ms151819(v=sql.105).aspx
and the lines that say
Microsoft SQL Server 2008 Express can serve as a Subscriber for all types of replication, providing a convenient way to distribute data to client applications that use this edition of SQL Server. When using SQL Server Express in a replication topology, keep the following considerations in mind:
SQL Server Express cannot serve as a Publisher or Distributor. However, merge replication allows changes to be replicated in both directions between a Publisher and Subscriber.
Blockquote
What if I new up some DataContexts, read some data, and then only wrap the SubmitChanges in a TransactionScope?
string conn1 = GetConn1();
string conn2 = GetConn2();
using (DataContext1 dc1 = new DataContext1(conn1))
{
List<Customer> customers = ReadSomeData(dc1);
ModifySomeCustomers(customers); //performs local modification to Customer instances
using (DataContext2 dc2 = new DataContext2(conn2))
{
List<Order> orders = ReadSomeData(dc2);
ModifySomeOrders(orders); //performs local modification to Order instances
using (TransactionScope scope = new TransactionScope())
{
dc1.SubmitChanges();
dc2.SubmitChanges();
scope.Complete();
}
}
}
The first SubmitChanges call is expected to fetch a connection from the pool and enlist that connection in the scope.
MS DTC is enabled - the second SubmitChanges call is expected to promote the transaction to "distributed", fetch a connection from the pool and enlist that connection in the scope.
I'm concerned that ReadSomeData may have left the connection open, so SubmitChanges doesn't fetch a connection from the pool, and therefore doesn't enlist the connection in the scope.
SubmitChanges will participate in the TransactionScope.
If SubmitChanges finds an ambient transaction it enlists to that transaction, otherwise it creates a transaction itself for the lifetime of the SubmitChanges method.
There is an MSDN Article about the transaction handling in SubmitChanges.
I'm using NHibernate 3.1.0 with the MySql Connector 6.3.5. As a general rule my repository methods are wrapped in an NHibernate transaction. However the service or application code calling the repository methods might also require a transaction scope - therefore the mixing of NHibernate transactions with .NET's TransactionScope. A simulated test looks like this:
[Test]
public void CanPerformNestedSave()
{
using (var tx = new TransactionScope())
{
var user = new AdminUser { Email = "user#test.com", Name = "Test User 1", Password = "123" };
using (ISession session = OpenSession())
{
using (var tx = session.BeginTransaction())
{
entity.ModifiedAt = DateTime.Now;
session.SaveOrUpdate(entity);
tx.Commit();
return entity;
}
}
tx.Complete();
}
}
The test fails with the following error:
NHibernate.TransactionException : Begin failed with SQL exception
----> System.InvalidOperationException : Nested transactions are not supported.
I've scoured the web to find a solution to this scenario and hopefully the community on StackOverflow can help.
I've blogged about this here.
In the blog post NServiceBus creates the outer TransactionScope for the handlers and the Nhibernate session and transactions are used inside the handler.