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

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.

Related

Could you please explain how to solve following problem?

// Verbinndung zum SQL-Server aufbauen
NpgsqlConnection SqlConn = new NpgsqlConnection(Program.Data.Settings.SQL_Server_ConnectionString);
SqlConn.Open();
NpgsqlDataAdapter daSql = new NpgsqlDataAdapter("SELECT * FROM " + Program.Data.Tab_SinterPersonal, SqlConn);
NpgsqlCommandBuilder cmds = new NpgsqlCommandBuilder(daSql);
daSql.DeleteCommand = cmds.GetDeleteCommand();
daSql.InsertCommand = cmds.GetInsertCommand();
daSql.UpdateCommand = cmds.GetUpdateCommand();
daSql.Update(Program.Data.dsSql.Tables[Program.Data.Tab_SinterPersonal]);
//NpgsqlConnection.Commit();
SqlConn.Commit();
SqlConn.Close();
Error:
NpgsqlConnection does not contain a definition for Commit and no extension method Commit accepting a first argument of type NpgsqlConnection could be found (are you missing a using directive or an assembly reference?)
Commit isn't something that's done on a connection, it's done on a transaction. The code should look like the following:
using var conn = new NpgsqlConnection(Program.Data.Settings.SQL_Server_ConnectionString);
SqlConn.Open();
using var transaction = conn.BeginTransaction(); // Begin the transaction
var daSql = new NpgsqlDataAdapter("SELECT * FROM " + Program.Data.Tab_SinterPersonal, SqlConn);
var cmds = new NpgsqlCommandBuilder(daSql);
daSql.DeleteCommand = cmds.GetDeleteCommand();
daSql.InsertCommand = cmds.GetInsertCommand();
daSql.UpdateCommand = cmds.GetUpdateCommand();
daSql.Update(Program.Data.dsSql.Tables[Program.Data.Tab_SinterPersonal]);
transaction.Commit(); // Commit the transaction

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.

Retrieve mssql primary key from query?

In C# Visual Studio Express Windows Forms:
How do I retrieve the primary key of a just executed insert query.
Here is my con+query code:
SqlConnection con = new SqlConnection(...);
SqlCommand command = con.CreateCommand();
command.CommandText = "INSERT INTO bestillinger (ha) VALUES (#ha);
command.Parameters.AddWithValue("#ha", listBox1.SelectedItem.ToString());
con.Open();
command.ExecuteNonQuery();
con.Close();
With a manual Close(), you risk leaking a connection if the code that uses it throws an exception. So please use using instead.
Assuming your PK is an identity column, the new value is most easily retrieved with scope_identity():
using (var con = new SqlConnection(...))
{
con.Open();
var command = con.CreateCommand();
command.CommandText = #"
INSERT INTO bestillinger (ha) VALUES (#ha);
select scope_identity();";
command.Parameters.AddWithValue("#ha", listBox1.SelectedItem.ToString());
var newPk = (long) command.ExecuteScalar();
}
As #Andomar said in his answer, ensure you properly close the connection.
Another way to return the value of the newly inserted identity field would be:
using (var con = new SqlConnection(...))
{
con.Open();
var command = con.CreateCommand();
command.CommandText = #"
INSERT INTO bestillinger (ha) OUTPUT inserted.[ID] VALUES (#ha);";
command.Parameters.AddWithValue("#ha", listBox1.SelectedItem.ToString());
var newPk = (long) command.ExecuteScalar();
}
[ID] would be replaced with the name of the identity field (or any field, or fields) that you want.

Inserting list records in database with stored procedures

I have a list of records inserting into a SQL Server database using a stored procedure. Currently I am doing it this way but is there any better way?
I am inserting 100-200 rows per/sec on peak hours of my app. The stored procedure only gets the values and inserts the new row
public void InsertRecords(List<stRecord> records)
{
foreach (var item in records)
{
if (CheckforDuplicateRecord(item) == false)
{
using (con = new SqlConnection(connectionString))
{
con.Open();
SqlCommand cmd = new SqlCommand(StoredProcedures.Service_Insert_record.ToString(), con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#item1", SqlDbType.NChar);
cmd.Parameters.Add("#item2", SqlDbType.NChar);
cmd.Parameters[0].Value = item.localUsername;
cmd.Parameters[1].Value = item.BetfairUsername;
try
{
cmd.ExecuteNonQuery();
}
catch (Exception exp)
{
throw exp;
}
}
}
}
}
This is exactly what table-valued parameters are for - you can pass your list in one shot.
In SQL Server:
CREATE TYPE dbo.Usernames AS TABLE
(
localUsername NVARCHAR(32),
BetfairUsername NVARCHAR(32)
);
GO
CREATE PROCEDURE dbo.Service_Insert_MultipleRows
#u AS dbo.Usernames READONLY
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO dbo.DestinationTable(localUsername, BetfairUsername)
SELECT localUsername, BetfairUsername FROM #u;
END
GO
Now in C#:
DataTable tvp = new DataTable();
tvp.Columns.Add(new DataColumn("localUsername"));
tvp.Columns.Add(new DataColumn("BetfairUsername"));
foreach(var item in records)
{
tvp.Rows.Add(item.localUsername, item.BetfairUsername);
}
using (con)
{
SqlCommand cmd = new SqlCommand("Service_Insert_MultipleRows", con);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter tvparam = cmd.Parameters.AddWithValue("#u", tvp);
tvparam.SqlDbType = SqlDbType.Structured;
con.Open();
cmd.ExecuteNonQuery();
}
One obvious thing you could do: create the SqlCommand only once at the beginning of the method - no point in creating it over and over and over again!
public void InsertRecords(List<stRecord> records)
{
using (con = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand(StoredProcedures.Service_Insert_record.ToString(), con))
{
cmd.CommandType = CommandType.StoredProcedure;
// are those paramters *REALLY* just 1 character long??
// that's what you have now, with the way you define it!
cmd.Parameters.Add("#item1", SqlDbType.NChar);
cmd.Parameters.Add("#item2", SqlDbType.NChar);
// otherwise, you need to define the LENGTH of the NCHAR parameter!
// cmd.Parameters.Add("#item2", SqlDbType.NChar, 15);
foreach (var item in records)
{
if (CheckforDuplicateRecord(item) == false)
{
cmd.Parameters["#item1"].Value = item.localUsername;
cmd.Parameters["#item2"].Value = item.BetfairUsername;
try
{
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
catch (Exception exp)
{
throw;
}
}
}
}

LINQ and TranscationScope not working

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

Resources