Sql server Insert slows down after inserting few rows - c#

I am inserting data in sql server 2008 R2 from web api. There are about 300 records that are inserted in 3 to 4 tables. First 20 to 30 records are easily inserted in few millisecond after that it will take few seconds to few minutes to insert records. The sql server is installed in Windows Server 2012 R2.
If I delete the same record after it is inserted and then again call the api to insert same data, it will just take 2 to 3 seconds to insert.
This is the api code
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using ProductsApp.ApplicationLogics;
using System.Web.Http.Cors;
using Newtonsoft.Json;
namespace ProductsApp.Controllers
{
[EnableCors(origins: "*", headers: "*", methods: "POST")]
public class DataPostController : ApiController
{
[AcceptVerbs("POST")]
public string DataPost([FromBody] List<Models.ReadingData> model)
{
if (model == null)
{
return "Data not found!";
}
string sql, id1;
string connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["APIConnectionString"].ConnectionString;
using (SqlConnection con = new SqlConnection(connectionString))
{
con.Open();
using (SqlTransaction tran = con.BeginTransaction())
{
foreach (var item in model)
{
sql = #"INSERT INTO TableA(Col1, Col2, Col3, Col4)
SELECT #Col1, #Col2, #Col3, #Col4;
SELECT SCOPE_IDENTITY();";
using (SqlCommand sqlCommand = new SqlCommand(sql, con, tran))
{
sqlCommand.Parameters.AddWithValue("#Col1", item.value1);
sqlCommand.Parameters.AddWithValue("#Col2", item.value2);
sqlCommand.Parameters.AddWithValue("#Col3", item.value3);
try
{
id1 = Convert.ToString(sqlCommand.ExecuteScalar());
if (item.amount > 0)
{
if (item.something != "0")
{
sql = #"INSERT INTO TableB(Col1, Col2, Col3)
SELECT #Col1, #Col2, #Col3;";
using (SqlCommand sqlCommand2 = new SqlCommand(sql, con, tran))
{
sqlCommand2.Parameters.AddWithValue("#Col1", id1);
sqlCommand2.Parameters.AddWithValue("#Col2", item.value5);
sqlCommand2.Parameters.AddWithValue("#FiscalYearId", item.value6);
try
{
sqlCommand2.ExecuteNonQuery();
}
catch (SqlException ex)
{
tran.Rollback();
return ex.Message;
}
}
}
}
if (item.advanceAmount > 0 || item.outstandingAmount > 0)
{
sql = #"UPDATE CustomersInfo SET AdvanceAmount=0, OutstandingAmount=0 WHERE CustomerId=#CustomerId;
UPDATE COAR SET IsClear=1 WHERE CustomerId=#CustomerId;
INSERT INTO COAR(FiscalYearId, CustomerId, EntryByUserId, OutstandingAmount, AdvanceAmount)
SELECT #FiscalYearId, #CustomerId, #EntryByUserId, #OutstandingAmount, #AdvanceAmount;";
}
else
{
sql = #"UPDATE CustomersInfo SET AdvanceAmount=0 WHERE CustomerId=#CustomerId;
UPDATE COAR SET IsClear=1 WHERE CustomerId=#CustomerId;";
}
using (SqlCommand sqlCommand2 = new SqlCommand(sql, con, tran))
{
sqlCommand2.Parameters.AddWithValue("#FiscalYearId", item.FiscalYearId);
sqlCommand2.Parameters.AddWithValue("#CustomerId", item.CustomerId);
sqlCommand2.Parameters.AddWithValue("#EntryByUserId", item.MeterReaderId);
sqlCommand2.Parameters.AddWithValue("#OutstandingAmount", item.outstandingAmount);
sqlCommand2.Parameters.AddWithValue("#AdvanceAmount", item.advanceAmount);
try
{
sqlCommand2.ExecuteNonQuery();
}
catch (SqlException ex)
{
tran.Rollback();
return ex.Message;
}
}
/*Insert Spot Fine (if any)*/
if (item.Fine > 0)
{
sql = #"INSERT INTO CreditSales(CreditSalesDateAD, CreditSalesDateBS, FiscalYearId,
CustomerId, ParticularsId, Amount, EntryByUserId, Status, MonthSN, MonthId)
SELECT #CreditSalesDateAD, #CreditSalesDateBS, #FiscalYearId,
#CustomerId, #ParticularsId, #Amount, #EntryByUserId, #Status, #MonthSN, #MonthId;";
using (SqlCommand sqlCommand4 = new SqlCommand(sql, con, tran))
{
sqlCommand4.Parameters.AddWithValue("CreditSalesDateAD", item.meterReadingDateAD);
sqlCommand4.Parameters.AddWithValue("CreditSalesDateBS", item.meterReadingDateBS);
sqlCommand4.Parameters.AddWithValue("FiscalYearId", item.FiscalYearId);
sqlCommand4.Parameters.AddWithValue("CustomerId", item.CustomerId);
sqlCommand4.Parameters.AddWithValue("ParticularsId", 5); //Always will be 5
sqlCommand4.Parameters.AddWithValue("Amount", item.Fine);
sqlCommand4.Parameters.AddWithValue("EntryByUserId", item.MeterReaderId);
sqlCommand4.Parameters.AddWithValue("Status", "0");
sqlCommand4.Parameters.AddWithValue("MonthSN", item.monthSN);
sqlCommand4.Parameters.AddWithValue("MonthId", item.MonthId);
try
{
sqlCommand4.ExecuteNonQuery();
}
catch (SqlException ex)
{
tran.Rollback();
return ex.Message;
}
}
}
/*If any tap repair complain*/
if (item.TapRepair == 1)
{
sql = #"INSERT INTO TapRepairs(ComplainDateAD, ComplainDateBS, FiscalYearId, CustomerId, ComplainTypeId,
RepairDateAD, RepairDateBS, RepairDescription, RepairByUserId)
SELECT #ComplainDateAD, #ComplainDateBS, #FiscalYearId, #CustomerId, #ComplainTypeId,
#RepairDateAD, #RepairDateBS, #RepairDescription, #RepairByUserId;";
using (SqlCommand sqlCommand5 = new SqlCommand(sql, con, tran))
{
sqlCommand5.Parameters.AddWithValue("#ComplainDateAD", item.meterReadingDateAD);
sqlCommand5.Parameters.AddWithValue("#ComplainDateBS", item.meterReadingDateBS);
sqlCommand5.Parameters.AddWithValue("#FiscalYearId", item.FiscalYearId);
sqlCommand5.Parameters.AddWithValue("#CustomerId", item.CustomerId);
sqlCommand5.Parameters.AddWithValue("#ComplainTypeId", item.Remarks);
sqlCommand5.Parameters.AddWithValue("#RepairDateAD", item.meterReadingDateAD);
sqlCommand5.Parameters.AddWithValue("#RepairDateBS", "");
sqlCommand5.Parameters.AddWithValue("#RepairDescription", "");
sqlCommand5.Parameters.AddWithValue("#RepairByUserId", item.MeterReaderId);
try
{
sqlCommand5.ExecuteNonQuery();
}
catch (SqlException ex)
{
tran.Rollback();
return ex.Message;
}
}
}
}
catch (SqlException ex)
{
if (ex.Message.Contains("MeterReadingEntries_FYID_MID_CID"))
{
//If meter reading entry already done
continue;
}
else
{
tran.Rollback();
return ex.Message;
}
}
}
}
tran.Commit();
con.Close();
con.Dispose();
}
}
return "ok";
}
}
}
Each table contains max 10 columns only.
What may be the cause? Is there anything wrong in the api? Why the insert is fast after the same record is deleted and re-inserted?
Update:
Profiler Image
Profiler Attached Image

In addition to creating stored procedures and sending a batch onto the stored procedure, I would definitely add that probably the execution plan for each query in each loop is different.
This has already been addressed on this post:
SQL Query slow in .NET application but instantaneous in SQL Server Management Studio
Look at the answer written by erikkallen

Related

Xamarin MysqlConnector weird NullReferenceException error

I'm wanting to make a small and simple mobile app for a school project, I know connecting to a db from a phone is not good for security reasons but basically only I will touch it.
So to connect my Xamarin app to Mysql I downloaded the extension MysqlConnector (https://www.nuget.org/packages/MySqlConnector/2.1.8?_src=template)
Everything seemed to work at first, but now I think that there is a problem in their library that is not compatible with Xamarin:
I seem to always get a nullreference exception at the second query at line
reader = cmd.ExecuteReader();. I don't know why, nothing is null, I've printed everything.
(I've put a comment on the line where it happens) I seriously doubt it is a problem in their library since they have 37.2M downloads in total. But maybe it is just a compatability conflict, but that makes it odd that the first query works then.
Here is all my current code:
using PuppyChinoBestelling.Views;
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
using MySqlConnector;
using System.Threading.Tasks;
namespace PuppyChinoBestelling.ViewModels
{
public class LoginViewModel : BaseViewModel
{
public Command LoginCommand { get; }
public string Mail { get; set; }
public string Pass { get; set; }
public LoginViewModel()
{
Pass = string.Empty;
Mail = string.Empty;
LoginCommand = new Command(OnLoginClicked);
}
private async void OnLoginClicked(object obj)
{
MySqlConnection conn = new MySqlConnection("private");
try
{
conn.Open();
Console.WriteLine("Conn opened!");
}
catch(Exception ex)
{
Console.WriteLine("Error " + ex.Message);
}
string sql = #"SELECT * FROM users WHERE email = #email;";
var cmd = conn.CreateCommand();
cmd.CommandText = sql;
cmd.Parameters.AddWithValue("#email", Mail);
var reader = cmd.ExecuteReader();
if (reader.HasRows)
{
sql = #"SELECT * FROM users WHERE email = #email;";
cmd = conn.CreateCommand();
cmd.Parameters.Clear();
cmd.CommandText = sql;
cmd.Parameters.AddWithValue("#email", Mail);
reader = cmd.ExecuteReader(); //null reference happening here idk why
string pwdHashed = reader.GetString(5);
bool validPwd = BCrypt.Net.BCrypt.Verify(Pass, pwdHashed);
conn.Close();
if (validPwd)
{
await Shell.Current.GoToAsync($"//{nameof(AboutPage)}");
}
else
{
Console.WriteLine("Foute logingegevens!");
}
}
else
{
Console.WriteLine("Je bestaat niet!");
}
}
}
}
Thanks in advance!
It's hard to say for certain, but it's likely the issue is because you are not closing the reader and command, and you can't have multiple commands on the same connection.
Also, you need to advance the reader using reader.Read.
In any case there is no need to run the command twice in the first place. You already had all the information on the first run.
You also need to dispose everything with using. This automatically closes the connection.
Don't SELECT *, just select the columns you need.
Ideally, you would calculate the hash for the given password, and send it to the database server to check, rather than pulling out the real password hash from the database (could be a security risk).
Don't store hashes as strings. Instead store them as binary with the varbinary data type, and cast to byte[] on the C# side.
Unclear why you are handling errors only for opening the connection, not for executing the command.
private async void OnLoginClicked(object obj)
{
const string sql = #"
SELECT Pass
FROM users
WHERE email = #email;
";
using (var conn = new MySqlConnection("private"))
using (var cmd = new MySqlCommand(sql, conn))
{
try
{
conn.Open();
Console.WriteLine("Conn opened!");
}
catch(Exception ex)
{
Console.WriteLine("Error " + ex.Message);
return; // no point continuing
}
cmd.Parameters.AddWithValue("#email", Mail);
using (var reader = cmd.ExecuteReader())
{
if (!reader.Read())
{
Console.WriteLine("Je bestaat niet!");
return; // no point continuing
}
string pwdHashed = (string)reader["Pass"];
conn.Close();
bool validPwd = BCrypt.Net.BCrypt.Verify(Pass, pwdHashed);
if (validPwd)
{
await Shell.Current.GoToAsync($"//{nameof(AboutPage)}");
}
else
{
Console.WriteLine("Foute logingegevens!");
}
}
}
}
An alternative method is to remove the reader altogether and use ExecuteScalar
private async void OnLoginClicked(object obj)
{
const string sql = #"
SELECT Pass
FROM users
WHERE email = #email;
";
using (var conn = new MySqlConnection("private"))
using (var cmd = new MySqlCommand(sql, conn))
{
try
{
conn.Open();
Console.WriteLine("Conn opened!");
}
catch(Exception ex)
{
Console.WriteLine("Error " + ex.Message);
return; // no point continuing
}
cmd.Parameters.AddWithValue("#email", Mail);
string pwdHashed = cmd.ExecuteScalar() as string;
conn.Close();
if (pwdHashed is null)
{
Console.WriteLine("Je bestaat niet!");
return; // no point continuing
}
bool validPwd = BCrypt.Net.BCrypt.Verify(Pass, pwdHashed);
if (validPwd)
{
await Shell.Current.GoToAsync($"//{nameof(AboutPage)}");
}
else
{
Console.WriteLine("Foute logingegevens!");
}
}
}

Max Open Cursors ORA-01000 using ODP.NET C# OracleDataReader

I am using the Oracle Data Provider for .NET version 4.112.3.0 to access an Oracle 9 database from an ASP.NET web application. Even though I explicitly Close and Dispose of the OracleDataReader and OracleConnection objects, I receive an ORA-01000 maximum open cursors exceeded error at times.
Most of my ODP.NET code is wrapped into a custom class.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Oracle.DataAccess.Client;
using System.Data;
namespace MyNamespace
{
public class MyOracleClass : IDisposable
{
private static string connectionString = "Data Source=myDB;Persist Security Info=True;User ID=myUser;Password=myPassword;";
private OracleConnection _conn;
private OracleTransaction _txn;
public MyOracleClass()
{
try
{
_conn = new OracleConnection(connectionString);
if (_conn.State != ConnectionState.Open)
_conn.Open();
_txn = _conn.BeginTransaction(IsolationLevel.ReadCommitted);
}
catch (Exception ex)
{
// Log Exception
throw ex;
}
}
public void Query(string query, ref OracleDataReader dr)
{
dr = null;
OracleCommand cmd = null;
try
{
if (_conn.State != ConnectionState.Open)
_conn.Open();
cmd = new OracleCommand(query, _conn);
dr = cmd.ExecuteReader();
}
catch (Exception ex)
{
// Log Exception
throw ex;
}
finally
{
if (cmd != null)
cmd.Dispose();
}
}
public void Disconnect()
{
try
{
if (IsConnectionOpen())
{
_txn.Rollback();
_conn.Close();
}
}
catch (Exception ex)
{
// Log Exception
}
}
public void Dispose()
{
Disconnect();
try
{
if (this._txn != null)
{
_txn.Dispose();
_txn = null;
}
}
catch (Exception ex)
{
// Log Exception
}
try
{
if (this._conn != null)
{
this._conn.Dispose();
}
}
catch (Exception ex)
{
// Log Exception
}
}
public bool IsConnectionOpen()
{
if (this._conn.State == ConnectionState.Open)
{
return true;
}
return false;
}
}
}
I then use the class in my program.
public void test()
{
OracleDataReader dr = null;
MyOracleClass oracleDb = null;
string query = "SELECT COL_1, COL_2, COL_3 FROM MY_TABLE";
try
{
oracleDb = new MyOracleClass();
oracleDb.Query(query, ref dr);
if(!dr.HasRows)
{
// No data found
}
else
{
while(dr.Read())
{
// Process data
}
}
}
catch(Exception ex)
{
// Log Exception
}
finally
{
if(dr != null)
{
dr.Close();
dr.Dispose();
}
oracleDb.Dispose();
}
}
My query returns an average of 500 rows. When I first experienced the issue, I decided to go to the database to see how many cursors were actually opening up. The OPEN_CURSORS parameter for my database is set to 100. For a given call to the query, I noticed there were 92 open cursors for this simple select query and would break the 100 cursor limit at times! Why would such a large number of cursors open when using the OracleDataReader?
Note, I've been testing this on a development system running Windows Server 2012 with IIS 8.0. I've also called the OracleConnection.ClearAllPools method once finished with the OracleConnection, but this didn't seem to help either. I also tested the query by populating a DataTable object by using the Fill method along with an OracleDataAdapter. Using this method only opened 3 cursors. Why is there such a variation in the number of cursors opened?

C# MySql Sometimes insert executed twice or not executed

I have to insert data to 3 tables in my MySql let say it was table1, table2 and table3
my problem is sometimes insert query for table2 is executed twice and sometimes it's not executed
Here is my code :
string Query = #"insert into table1(SellCode, SellDate, SellType, Discount, BuyerCode)
values (#SellCode, #SellDate, #SellType, #Discount, #BuyerCode)";
using (MySqlConnection conExpDB = new MySqlConnection(ConString))
using (MySqlCommand cmdExpDB = new MySqlCommand(Query, conExpDB))
{
try
{
conExpDB.Open();
cmdExpDB.Parameters.AddWithValue("#SellCode", SellCode);
cmdExpDB.Parameters.AddWithValue("#SellDate", DateTime.Now);
cmdExpDB.Parameters.AddWithValue("#SellType", "Retail");
cmdExpDB.Parameters.AddWithValue("#Discount", txtDiscount.Text);
cmdExpDB.Parameters.AddWithValue("#BuyerCode", "1");
int rowsUpdated = cmdExpDB.ExecuteNonQuery();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}//end try
}//end using
string QueryB = #"insert into table2(PaymentCode, PaymentAmount,
SellCode, PaymentDate)
values (#PaymentCode, #PaymentAmount, #SellCode, #PaymentDate)";
using (MySqlConnection conExpDB = new MySqlConnection(ConString))
using (MySqlCommand cmdExpDB = new MySqlCommand(QueryB, conExpDB))
{
try
{
conExpDB.Open();
cmdExpDB.Parameters.AddWithValue("#PaymentCode", paymentcode);
cmdExpDB.Parameters.AddWithValue("#PaymentAmount", PaymentAmount);
cmdExpDB.Parameters.AddWithValue("#SellCode", SellCode);
cmdExpDB.Parameters.AddWithValue("#PaymentDate", DateTime.Now);
int rowsUpdated = cmdExpDB.ExecuteNonQuery();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}//end try
}//end using
foreach (DataGridViewRow row in GridView.Rows)
{
string QueryDetail = #"insert into table3(SellDetailCode, SellCode,
ItemCode, Qty,
Price)
values (#SellDetailCode, #SellCode, #ItemCode, #Qty,
#Price)";
using (MySqlConnection conExpDB = new MySqlConnection(ConString))
using (MySqlCommand cmdExpDB = new MySqlCommand(QueryDetail, conExpDB))
{
try
{
conExpDB.Open();
cmdExpDB.Parameters.AddWithValue("#SellDetailCode", SellDetailCode);
cmdExpDB.Parameters.AddWithValue("#SellCode", SellCode);
cmdExpDB.Parameters.AddWithValue("#ItemCode", ItemCode);
cmdExpDB.Parameters.AddWithValue("#Qty", Qty);
cmdExpDB.Parameters.AddWithValue("#Price", Price);
int rowsUpdated = cmdExpDB.ExecuteNonQuery();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}//end try
}//end using
}//end foreach
Is there any effective method to detect the queries are inserted twice or not executed? Or is there any problem with my queries?
Because it's happened very rare it's difficult for me fixed this error

SqlCeDataReader Read() returning false

I am working on a card game which uses a database to store and retrieve cards. Unfortunately I am having trouble retrieving data from the database.
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CardGame
{
class Program
{
static void Main(string[] args)
{
Card c = new Card();
Card d;
c.Name = "TestCard";
c.Pack = "Pack";
c.Value = 5;
c.Color = Colors.green;
c.Description = "Describing stuff";
//Database.CreateCardTable(); (Already created)
Database.InsertCard(c);
d = Database.RetrieveCard("TestCard");
Console.WriteLine(d.Name);
Console.ReadLine();
}
}
}
Database.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlServerCe;
using System.Data;
using System.Data.SqlClient;
namespace CardGame
{
class Database
{
public static void CreateCardTable()
{
string sqlStr;
SqlCeConnection CardConn = new SqlCeConnection(Properties.Settings.Default.CardsConnectionString);
sqlStr = "CREATE TABLE Data " +
"(Name NVARCHAR(50), " +
"Pack NVARCHAR(50), " +
"Value INT, " +
"Color INT," +
"Description NVARCHAR(200))";
SqlCeCommand CardComm = new SqlCeCommand(sqlStr, CardConn);
try
{
CardConn.Open();
CardComm.ExecuteNonQuery();
Console.WriteLine("Tables Created Successfully!");
}
catch (System.Exception ex)
{
Console.WriteLine(ex.ToString());
Console.WriteLine("Error creating tables.");
}
finally
{
if (CardConn.State == ConnectionState.Open)
{
CardConn.Close();
}
}
}
public static void InsertCard(Card c)
{
SqlCeConnection CardConn = new SqlCeConnection(Properties.Settings.Default.CardsConnectionString);
try
{
CardConn.Open();
SqlCeCommand insertCommand = new SqlCeCommand("INSERT INTO Data VALUES(#Name, #Pack, #Value, #Color, #Description)", CardConn);
insertCommand.Parameters.Add("Name", c.Name);
insertCommand.Parameters.Add("Pack", c.Pack);
insertCommand.Parameters.Add("Value", c.Value);
insertCommand.Parameters.Add("Color", c.Color);
insertCommand.Parameters.Add("Description", c.Description);
Console.WriteLine("Card inserted successfully");
}
catch
{
Console.WriteLine("Some kind of error.");
}
finally
{
if (CardConn.State == ConnectionState.Open)
{
CardConn.Close();
}
}
}
public static Card RetrieveCard(string name)
{
Card c = new Card();
SqlCeConnection CardConn = new SqlCeConnection(Properties.Settings.Default.CardsConnectionString);
try
{
CardConn.Open();
SqlCeCommand retrieveCommand = new SqlCeCommand("SELECT * FROM Data WHERE Name=#Name", CardConn);
retrieveCommand.Parameters.Add("Name", name);
SqlCeDataReader reader = retrieveCommand.ExecuteReader();
while (reader.Read())
{
Console.WriteLine("Reader: " + reader["Name"].ToString());
c.Name = (string)reader["Name"];
//read rest
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
return c;
}
public void CreateAccountDB(string DBName)
{
}
}
}
When I run insert card I do get a success message (at the end of the try statement). When I do Database.RetrieveCard("TestCard"); it reaches the line while (reader.Read()) but my program does not reach the code inside of the while statement. How can I fix my code so that I can read cards from the database?
I built the command to insert a card into the database but I never actually executed it. So nothing was ever inserted so when I go to retrieve the card it will return nothing because there is nothing in the database!
I changed
try
{
CardConn.Open();
SqlCeCommand insertCommand = new SqlCeCommand("INSERT INTO Data VALUES(#Name, #Pack, #Value, #Color, #Description)", CardConn);
insertCommand.Parameters.Add("Name", c.Name);
insertCommand.Parameters.Add("Pack", c.Pack);
insertCommand.Parameters.Add("Value", c.Value);
insertCommand.Parameters.Add("Color", c.Color);
insertCommand.Parameters.Add("Description", c.Description);
Console.WriteLine("Card inserted successfully");
}
to
try
{
CardConn.Open();
SqlCeCommand insertCommand = new SqlCeCommand("INSERT INTO Data VALUES(#Name, #Pack, #Value, #Color, #Description)", CardConn);
insertCommand.Parameters.Add("Name", c.Name);
insertCommand.Parameters.Add("Pack", c.Pack);
insertCommand.Parameters.Add("Value", (int)c.Value);
insertCommand.Parameters.Add("Color", (int)c.Color);
insertCommand.Parameters.Add("Description", c.Description);
insertCommand.ExecuteNonQuery();
Console.WriteLine("Card inserted successfully");
}

Running a CREATE PROCEDURE script programmatically

I'm trying to develop a little app that will run a CREATE PROCEDURE script. A simple example:
IF EXISTS (SELECT * FROM sysobjects WHERE type = 'P' AND name = 'ap_get_roles_in_system')
BEGIN
DROP Procedure [dbo].[ap_get_roles_in_system]
END
GO
CREATE PROCEDURE [dbo].[ap_get_roles_in_system]
(
#system_id int
)
AS
SELECT * FROM roles
GO
GRANT EXEC ON [dbo].[ap_get_roles_in_system] TO PUBLIC
GO
If I load this text up in a string, and run it by way of ExecuteNonQuery(), the first item, which drops the stored procedure, works fine, but instead of running the Create it finds a syntax error with the parameter of the stored procedure, namely: it hasn't been declared.
In short, instead of trying to run the CREATE, it is somehow trying to run the script as a script, not a CREATE. Not sure what the correct wording would be.
The script above works great if pasted into Sql Management Studio.
Here's the code I am executing:
public string RunSql(string Sql)
{
string result = string.Empty;
_conn.Open();
SqlCommand cmd = new SqlCommand(Sql, _conn);
cmd.CommandType = CommandType.Text;
try
{
cmd.ExecuteNonQuery();
result = "Succeeded";
}
catch (SqlException ex)
{
result = ex.Message;
}
return result;
}
#RichardSchneider's answer led me to the solution I found, but I thought at this late date, since there have been so many views, that I should post the code that solved the problem, which Richard's answer led me to. Here it is, an entire class named SqlAction. Note that I split the entire text with "GO", and then put the components into an array, executing each component in turn:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;
namespace SProcRunner
{
public class SqlAction
{
public SqlAction(string connString)
{
SqlConnectionStringBuilder sb = new SqlConnectionStringBuilder(connString);
_conn = new SqlConnection(sb.ToString());
}
private SqlConnection _conn;
public string RunSql(string Sql)
{
string result = string.Empty;
// split the sql by "GO"
string[] commandText = Sql.Split(new string[] { String.Format("{0}GO{0}", Environment.NewLine) }, StringSplitOptions.RemoveEmptyEntries);
_conn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = _conn;
cmd.CommandType = CommandType.Text;
for (int x = 0; x < commandText.Length; x++)
{
if (commandText[x].Trim().Length > 0)
{
cmd.CommandText = commandText[x];
try
{
cmd.ExecuteNonQuery();
result = "Command(s) completed successfully.";
}
catch (SqlException ex)
{
result = String.Format("Failed: {0}", ex.Message);
break;
}
}
}
if (_conn.State != ConnectionState.Closed) _conn.Close();
return result;
}
}
}
Remove the "GO" lines from the SQL.

Categories