LINQ and TranscationScope not working - sql-server

I am using LINQ select statement wrapped in a TransactionScope (to change the locking) but according to SQL Profiler, it doesn't seem to be working. My code looks like:
using (var ts = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadUncommitted} ))
{
using (myDBDataContext dbPKC = new myDBDataContext(conn))
{
...query...
ts.Complete();
return xmlMachine;
}
}
Now I would expect SQL Profiler to show BatchStarting and BatchComplete for my select statement. But it shows RPC:Completed. Why? when I run this code:
using (SqlConnection conn1 = new SqlConnection())
{
conn1.ConnectionString = WebConfigurationManager.ConnectionStrings["myConnectionString"].ToString(); ;
conn1.Open();
using (SqlTransaction trans1 = conn1.BeginTransaction(System.Data.IsolationLevel.ReadUncommitted))
{
SqlCommand cmd = new SqlCommand("select * from Machines where pkID = 5");
cmd.Connection = conn1;
cmd.Transaction = trans1;
SqlDataReader reader = cmd.ExecuteReader(); // just execute something
}
}
It shows BatchStarting and BatchComplete. Why doesn't LINQ seem to "see" the TransactionScope?
Also is there a way to confirm that my isolationlevel is correct through Profiler? I can only see the initial connection's isolation level through Audit Login. No "update" is displayed to show that it was changed or what each isolationlevel each query is using.
Any help would be wonderful!
Also, this code is running in a WCF (3.5) service connecting to SQL Server 2008

UPDATED:
Try something like this to check isolation level:
using(TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew, options))
{
//Verify Scope using DBCC USEROPTIONS
SqlCommand cmd = (SqlCommand)ctxt.Connection.CreateCommand();
cmd.CommandText = "DBCC USEROPTIONS";
SqlDataReader r = cmd.ExecuteReader();
while (r.Read())
{
Console.WriteLine(r.GetValue(0) + ":" + r.GetValue(1));
}
}
ADDED:
Look for SET TRANSACTION ISOLATION LEVEL

Related

Conversion failed when converting from a character string to uniqueidentifier - Doesn't Rollback the transaction

The actual issue is not this - "Conversion failed when converting from a character string to uniqueidentifier" but the issue is that, the transaction doesn't get rolled back after you hit the issue.
My code here,
var connectionstring = "Server= ****; Database= ****; Integrated Security=True;";
var errorInformation = new List<string>();
using (SqlConnection objConn = new SqlConnection(connectionstring))
{
objConn.Open();
var objTrans = objConn.BeginTransaction(); // Begins here
var sql = $"insert into tblProject values('7', 'TestProject')";
SqlCommand insertCommand = new SqlCommand(sql, objConn, objTrans);
try
{
insertCommand.ExecuteNonQuery();
// ProjectID is a unique Identifier in database
SqlCommand cmd = new SqlCommand("SELECT * FROM SOMEOTHERTABLE WHERE PROJECTID=''", objConn, objTrans);
cmd.CommandType = CommandType.Text;
var dataTable = new DataTable("SomeTableName");
using (var adapter = new SqlDataAdapter(cmd))
{
var dt = adapter.Fill(dataTable); // Exception happens here
}
objTrans.Commit(); // Commit here
}
catch (Exception ex)
{
errorInformation.Add(ex.Message);
}
var sql1 = $"insert into tblProject values('8', 'TestProject')";
SqlCommand objCmd2 = new SqlCommand(sql1, objConn, objTrans);
objCmd2.ExecuteNonQuery();
if (errorInformation.Any())
{
objTrans.Rollback(); // Rollback here
}
}
The query that gets executed after the exception, using the same connection object will not rollback. This is a bug that Microsoft needs to look into. Otherwise their rollback feature is not reliable.
I would expect either my second insert command to fail or my rollback to be successful.

How to copy all schema from one database to other database (created at runtime)?

I have used schema for tables for one database,so how to copy all schema from one database to other database(database created at runtime)
string sql = "create database " + str1;
SqlCommand command = new SqlCommand(sql, connection);
connection.Open();
command.ExecuteNonQuery();
Response.Write("database created");
connection.Close();
string sqll = "(select * into " + str1 + ".cost_category.cost_category_info
from ERPAccounting.cost_category.cost_category_info where 1=2)
(select * into " + str1 + ".dbo.cost_centre_info from
ERPAccounting.cost_centre.cost_centre_info where 1=2)"
connection.Open();
SqlDataAdapter ad = new SqlDataAdapter(sqll, connection);
DataSet ds = new DataSet();
ad.Fill(ds);
Using C#, object DDL can be obtained by using SMO objects and then executed in the database where the objects need to be copied to. In the example below, references to Microsoft.SqlServer.Management.Smo, Microsoft.SqlServer.ConnectionInfo, Microsoft.SqlServer.Management.Sdk.Sfc, and System.Data.SqlClient are necessary. The DDL is first obtained from the SMO objects, then it used as the CommandText for the SqlCommand that is executed in the destination database. This example is for tables, but other objects (views, stored procedures, etc.) can also be copied using this method.
//set initial catalog to destination database
string connStr = #"Data Source=YourServer;Initial Catalog=DestinationDatabase;Integrated Security=SSPI;";
using (SqlConnection conn = new SqlConnection(connStr))
{
//set source server and database using SMO objects
Server srv = new Server(#"YourServer");
srv.ConnectionContext.LoginSecure = true;
srv.ConnectionContext.StatementTimeout = 600;
Database db = srv.Databases["SourceDatabase"];
//configure Scripter for DDL
Scripter script = new Scripter(srv);
ScriptingOptions scriptOpt = new ScriptingOptions();
//SQL command to execute DDL in destination database
SqlCommand sql = new SqlCommand();
sql.Connection = conn;
conn.Open();
//this can changed to views, SPs, etc. as needed
foreach (Table t in db.Tables)
{
//check for system objects
if (!t.IsSystemObject)
{
StringCollection sc = t.Script(scriptOpt);
foreach (string s in sc)
{
//assign and execute DDL
sql.CommandText = s;
sql.ExecuteNonQuery();
}
}
}
}

Linq To Sql Conversation In Wcf Service

Can you please provide an answer following sql query to linq . I have some knowledge about linq but i am confused about sql reader object ..
public AccountBalanceRequest AccountBalanceCheek(AccountBalanceRequest accountNumber)
{
using (SqlConnection conn = new SqlConnection(ConnectionString))
{
conn.Open();
var cmd = new SqlCommand("SELECT Account_Type,Account_Fees,Account_Balance,Over_Draft_Limit FROM Current_Account_Details WHERE Account_Number = '" + accountNumber.Account_Number + "'", conn);
cmd.CommandType = CommandType.Text;
var reader = cmd.ExecuteReader();
//read the result of the execute command.
while (reader.Read())
{
//assuming that your property is the same as your table schema. refer to your table schema Current_Account_Details
accountNumber.Account_Type = reader["Account_Type"].ToString();
accountNumber.Account_Fee = reader["Account_Fees"].ToString();
accountNumber.Account_Balance = reader["Account_Balance"].ToString();
accountNumber.Over_Draft_Limit = reader["Over_Draft_Limit"].ToString();
}
return accountNumber;
}
}
First you have to have DbContext which you must instantiate in using(usual practice):
using (DbContext db = new DbContext())
{
var results = (from ad in db.Current_Account_Details
where ad.Account_Number == accountNumber.Account_Number
select ad).ToList();
}
Make sure you have created the object data model from database.
I do not get the other part of your post but this would be the general idea of how to write Linq2Entities queries.

How can we use both sql and oracle database connection using one object only

I wants to fetch the data from database using C++.Net. I need to do this irrespective of db used in the system. But i don't want to change my code for each database. I am looking for a solution in C++.Net, please do help..
This is what i have now;
Oracle:
OracleConnection *myOracleConnection;
OracleDataAdapter * myDataAdapter;
DataSet * myDataSet;
myOracleConnection = new OracleConnection(S"Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.2.175)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=SCDB)));User Id=user;Password=pw;");
myOracleConnection->Open();
myDataAdapter = new OracleDataAdapter(S"select dbms_xmlgen.getxml(' select * from SampleTable') from dual ",myOracleConnection);
myDataSet = new DataSet("Sample");
Sql:
`SqlConnection *mySQLConnection;
SqlDataAdapter * myDataAdapter;
DataSet * myDataSet;
mySQLConnection = new SqlConnection(S"Data Source=(local);Initial Catalog=myDb;User Id=user;Password=pw;");
mySQLConnection->Open();
myDataAdapter = new SqlDataAdapter(S"select * from [SampleTable]",mySQLConnection);
myDataSet = new DataSet("Sample");`
i wants to do both connection using one connection object. Is there any idea to achieve this???
I can't give you c++ code, but I can help you how to do it. It will be difficult to do it in one connection, but your can get a DataSet back which will work, and you only have to do the code once.
Create a method will return a DataSet, and pass the query as well as what type of connection should be used, in this method depending on tour connection type you do your query and return your result.
You can also add a connectionstring if you wish.
Something like this (it is c# though)
DataSet GetDataSet(string sqlQuery, ConnectionType connType)
{
DataSet dataset = new DataSet("aDataSet");
using (DataTable table = dataset.Tables.Add("aDataTable"))
{
switch (connType)
{
case ConnectionType.MSSQL:
using (var conn = new SqlConnection("Data Source=(local);Initial Catalog=myDb;User Id=user;Password=pw"))
{
using (var cmd = new SqlCommand(sqlQuery, conn))
{
conn.Open();
using (var reader = cmd.ExecuteReader())
{
table.Load(reader);
}
}
}
break;
case ConnectionType.Oracle:
using (var conn = new OracleConnection("Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.2.175)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=SCDB)));User Id=user;Password=pw"))
{
using (var cmd = new OracleCommand(sqlQuery, conn))
{
conn.Open();
using (var reader = cmd.ExecuteReader())
{
table.Load(reader);
}
}
}
break;
default:
break;
}
}
return dataset;
}
enum ConnectionType { MSSQL, Oracle }

The following code can’t cause a deadlock, and yet I get Transaction ( Process ID 54 ) was deadlocked …

Service operation MyMethod(int id) retrieves particular row ( based on an id parameter ) from a single DB table and just before it returns it also saves that state back to the table. If two calls ( first call happens within transaction T1 while second within transaction T2 ) to MyMethod() are made at the same time, then service will try to execute the two calls concurrently. Since both T1 and T2 try to access same DB table, one of the two transaction will be granted access to the resource, while other should get blocked until the original transaction commits or aborts. But instead I get an exception Transaction ( Process ID 54 ) was deadlocked on lock resources with another process and has been chosen as the deadlock victim
I don’t understand reasoning behind throwing deadlock exception since as far as I can tell there isn’t any danger of a deadlock. For one thing, the two transactions accessed and operated on different rows. Why wasn’t instead the DB resource just locked until original transaction committed or aborted?!
Here is the code:
[ServiceContract]
public interface IService
{
[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
void Process(int id);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, IncludeExceptionDetailInFaults=true)]
public class Service : IService
{
string state_Data = "";
[OperationBehavior(TransactionScopeRequired = true)]
public void Process(int id)
{
GetState(id);
Thread.Sleep(6000);
SaveState(id);
}
private void GetState(int id)
{
using (SqlConnection con = new SqlConnection())
{
con.ConnectionString = "data source=localhost; initial catalog=WCF; integrated security=sspi;";
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "SELECT * FROM StateTable WHERE id = #id";
cmd.Parameters.Add("#id", SqlDbType.Int).Value = id;
cmd.Connection = con;
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
if (reader.Read())
state_Data = reader["State"].ToString();
}
}
private bool SaveState(int id)
{
using (SqlConnection con = new SqlConnection())
{
con.ConnectionString = "data source = localhost; initial catalog=WCF; integrated security=sspi;";
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "UPDATE StateTable SET State=#State WHERE Id = #id";
cmd.Parameters.Add("#id", SqlDbType.Int).Value = id;
cmd.Parameters.Add("#State", SqlDbType.NVarChar).Value = state_Data;
cmd.Connection = con;
con.Open();
int ret = cmd.ExecuteNonQuery();
return ret == 1;
}
}
}
EDIT:
In case this will help, here is client code:
FIRST CLIENT:
ServiceClient proxy = new ServiceClient("WSDualHttpBinding_IService");
using (TransactionScope scope = new TransactionScope())
{
proxy.Process(1);
scope.Complete();
}
SECOND CLIENT:
ServiceClient proxy = new ServiceClient("WSDualHttpBinding_IService");
using (TransactionScope scope = new TransactionScope())
{
proxy.Process(2);
scope.Complete();
}
Thank you
Actually this code is a guaranteed deadlock. There can be any number of successful GetState calls on the same ID, all succeeding, since they all acquire (and retain, due to the serializable transaction scope) shared locks and therefore are compatible. Any subsequent attempt to SaveState will block, because of the multitude of shared locks are all incompatible with the X lock needed for the update. The next SaveState will deadlock. 100% repro, guaranteed, every time.
You should use optimistic concurrency instead if you care about performance. If performance is irrelevant then the GetState should lock the state exclusively, eg. by providing an XLOCK hint.
Of course, I assume there is a clustered index on ID in StateTable.

Resources