My database is in SQL Server and I use Linq-to-SQL. I used from SP(Save cards) .
I put breakpoint in my code, when arrive at rdr = cmm.ExecuteReader(); get me exception!!!
private void btnSave_Click(object sender, EventArgs e)
{
PersianCalendar jc = new PersianCalendar();
string SaveDate = jc.GetYear(DateTime.Now).ToString();
int from=Convert.ToInt32(txt_barcode_f.Text);
int to=Convert.ToInt32(txt_barcode_t .Text);
int quantity=Convert.ToInt32(to-from);
int card_Type_ID=Convert.ToInt32(cmb_BracodeType .SelectedValue);
int[] arrCardNum = new int[quantity];
arrCardNum[0]=from;
for (int i = from; i < to;i++ )
{
for(int j=0; j<quantity ;j++)
{
arrCardNum[j]=from+j;
int r = arrCardNum[j];
sp.SaveCards(r, 2, card_Type_ID, SaveDate, 2);
}
}
}
public void SaveCards(int Barcode_Num, int Card_Status_ID, int Card_Type_ID, string Save_Date, int Save_User_ID)
{
IDbCommand cmm;
cmm = Linq.Connection.CreateCommand();
try
{
cmm.Parameters.Add(new SqlParameter("#Barcode_Num", Barcode_Num));
cmm.Parameters.Add(new SqlParameter("#Card_Status_ID", 2));
cmm.Parameters.Add(new SqlParameter("#Card_Type_ID", Card_Type_ID));
cmm.Parameters.Add(new SqlParameter("#SaveDate", Save_Date));
cmm.Parameters.Add(new SqlParameter("#Save_User_ID", Save_User_ID));
cmm.CommandText = "SaveCards";
cmm.Connection.Open();
cmm.Connection = Linq.Connection;
cmm.CommandType = CommandType.StoredProcedure;
IDataReader rdr = null;
**rdr = cmm.ExecuteReader();**
while (rdr.Read())
{
Console.Write(" All Insert ! " + "\n");
}
}
catch (SqlException ex)
{
SqlExceptionHandler(ex, Save_User_ID);
}
catch (Exception ex)
{
PopularEexceptionHandler(ex, Save_User_ID);
}
finally
{ cmm.Connection.Close(); }
}
when excute sp, show no result and display this:
when execute sp , display this:The INSERT statement conflicted with the CHECK constraint "CK_BarCode_Num". The conflict occurred in database "Parking", table "dbo.TBL_Cards", column 'BarCode_Num'. The statement has been terminated. No rows affected. (0 row(s) returned) #RETURN_VALUE = -6
You're a bit chaotic on how you set up your connection and command..... e.g. you open the connection before you even assign it! How is that going to work??
My recommendation would be this order (based on the principle first do all the setup before opening the connection, and furthermore open the connection as late as possible, close it as quickly as possible) :
IDbCommand cmm = Linq.Connection.CreateCommand();
try
{
// define name and type of command
cmm.CommandText = "SaveCards";
cmm.CommandType = CommandType.StoredProcedure;
// assign connection
cmm.Connection = Linq.Connection;
// define parameters
cmm.Parameters.Add(new SqlParameter("#Barcode_Num", Barcode_Num));
cmm.Parameters.Add(new SqlParameter("#Card_Status_ID", 2));
cmm.Parameters.Add(new SqlParameter("#Card_Type_ID", Card_Type_ID));
cmm.Parameters.Add(new SqlParameter("#SaveDate", Save_Date));
cmm.Parameters.Add(new SqlParameter("#Save_User_ID", Save_User_ID));
// only now - after all the setup - open the connection, read the data
cmm.Connection.Open();
IDataReader rdr = rdr = cmm.ExecuteReader();
while (rdr.Read())
{
....
}
}
To catch the errors that the execution throws, replace your catch block for the SqlException with this:
catch (SqlException ex)
{
StringBuilder sbErrors = new StringBuilder();
foreach (SqlError error in ex.Errors)
{
sbErrors.AppendLine(error.Message);
}
string allErrors = sbErrors.ToString();
}
and debug into that catch block - what is the allErrors string in the end??
Update: after a chat session, we know finally know what the message in the SQL exception is:
The INSERT statement conflicted with the CHECK constraint "CK_BarCode_Num". The conflict occurred in database "Parking", table "dbo.TBL_Cards", column 'BarCode_Num'.
Now we're trying to find out what that constraint is / does and why it gets violated....
I think it could be that you have open the connection and assigning another connection before executing the reader.
cmm.CommandText = "SaveCards";
//cmm.Connection.Open(); You should open the connection after assigning it
cmm.Connection = Linq.Connection;
cmm.CommandType = CommandType.StoredProcedure;
cmm.Connection.Open(); //Open it here
SqlDataReader rdr = cmm.ExecuteReader();
Related
I send SQL command to ODBC to be able to insert into another application's database.
Looping in selected forms and its rows, I create command.
"OnTransactionCommand" simply returns an sql string of related row to be sent to ODBC for table 'STOCKTRN'
But the problem is that my integration function sometimes returns the error below:
ERROR [HY000] [TOD][ODBC][GENESIS]VISION: Cannot insert into 'STOCKTRN',No locks available
I am not sure but it is probably about the number of execution. With similar data when I test it with 15-20 records it works nicely. But Working with +50 records it returns error.
Is there any kind of limit or I am missing another part ?
My function:
private void MTransaction(MyGridView gvList)
{
try
{
var m_Integration = ctx.Integration.Take(1).FirstOrDefault();
if (m_Integration != null)
{
DbProviderFactory mFactory= DbProviderFactories.GetFactory(m_Integration.ServerType);
using (DbConnection dbcon = mFactory.CreateConnection())
{
dbcon.ConnectionString = m_Integration.ConnString;
for (int i = 0; i < gvList.RowCount; i++)
{
if (Convert.ToBoolean(gvList.GetRowCellValue(i, "Select")))
{
dbcon.Open();
int m_TransactionId = Convert.ToInt32(gvList.GetRowCellValue(i, "Id"));
MTransaction m_Transaction = ctx.Transaction.Where(c => c.Id == m_TransactionId).FirstOrDefault();
using (DbTransaction dbtr = dbcon.BeginTransaction())
{
try
{
using (DbCommand dbcmd = dbcon.CreateCommand())
{
dbcmd.Transaction = dbtr;
if (m_Transaction != null)
{
int TransactionRowCounter = 1;
foreach (var item in m_Transaction.TransactionRow)
{
dbcmd.CommandText = OnTransactionCommand(m_Transaction, item, TransactionRowCounter);
dbcmd.ExecuteNonQuery();
TransactionRowCounter++;
}
}
dbtr.Commit();
}
}
catch (Exception err)
{
dbtr.Rollback();
dbcon.Close();
XtraMessageBox.Show(err.Message);
continue;
}
}
dbcon.Close();
}
}
}
}
}
catch (Exception err)
{
SuccessMessage = "Error:\n" + err.Message;
}
}
I have a discord bot that gets its data from a SQLite Database. I am using the System.Data.SQLite-Namespace
My problem is this code part:
m_dbConnection.Open();
SQLiteDataReader sqlite_datareader;
SQLiteCommand sqlite_cmd;
sqlite_cmd = m_dbConnection.CreateCommand();
sqlite_cmd.CommandText = SQLCommand; //SQLCommand is a command parameter
sqlite_datareader = sqlite_cmd.ExecuteReader();
while (sqlite_datareader.Read())
{
int i = 0;
while (true)
{
try
{
string temp = "";
try
{
temp = sqlite_datareader.GetString(i).ToString();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
try
{
temp = sqlite_datareader.GetInt32(i).ToString();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
break;
}
}
output.Add(temp);
i++;
}
catch (Exception)
{
break;
}
}
}
For this example the variable SQLCommand is "SELECT Money FROM Users WHERE UserId = 12345 AND ServerID = 54321".
When I execute this command in an SQL Editor, , I get the value "10". So the command works. Now when I pass this command in my method, to get the data, I just got with the editor, I get the error Specified cast is not valid. at the code temp = sqlite_datareader.GetString(i).ToString();.
The value i is 0, to get the very first row that the sql command selected. I don't know why this happens, every other SQLite-Command works and gives me what I want. Why isn't this command working too?
Try using it this way
while (sqlite_datareader.Read())
{
for (int i = 0; i < reader.FieldCount; i++)
{
var ColName = reader.GetName(i);
var colValue = reader[i];
}
}
Please note that
while (sqlite_datareader.Read()){..}
the purpose of the above statement is to fetch all the rows.
therefore I would like to mention the problems in your code
1-) while(true){...}
is infinite loop, ofcourse in this scenario it would hit the break and quit but still this is not a good practice
2-) int i = 0;
you have declared and increased it by one inside the while loop. The problem here is that:
say you have 100 rows and 10 columns; this means that i would be increased to 99
however you have 10 colums, trying to get an invalid column value would give you an error
putting your code in try catch/ nested try catch statements would solve the issue however it's a nasty solution.
So this is a little bit code-ceptionlike.
I have a function that is checking the last ID in a table, this function is called within another function. At the end of that function, I have another function that's opening another datareader.
Error:
There is already an open Datareader associated with this connection which must be closed first.
getLastIdfromDB()
public string getLastIdFromDB()
{
int lastIndex;
string lastID ="";
var dbCon = DB_connect.Instance();
if (dbCon.IsConnect())
{
MySqlCommand cmd2 = new MySqlCommand("SELECT ID FROM `competitor`", dbCon.Connection);
try
{
MySqlDataReader reader = cmd2.ExecuteReader();
while (reader.Read())
{
string item = reader2["ID"].ToString();
lastIndex = int.Parse(item);
lastIndex++;
lastID = lastIndex.ToString();
}
}
catch (Exception ex)
{
MessageBox.Show("Error:" + ex.Message);
}
}
return lastID;
}
This function is later-on used in this function:
private void addPlayerBtn_Click(object sender, EventArgs e)
{
ListViewItem lvi = new ListViewItem(getLastIdFromDB());
.........................................^
... HERE
...
... irrelevant code removed
.........................................
var dbCon = DB_connect.Instance();
if (dbCon.IsConnect())
{
MySqlCommand cmd = new MySqlCommand("INSERT INTO `competitor`(`ID`, `Name`, `Age`) VALUES(#idSql,#NameSql,#AgeSql)", dbCon.Connection);
cmd.Parameters.AddWithValue("#idSql", getLastIdFromDB());
cmd.Parameters.AddWithValue("#NameSql", playerName.Text);
cmd.Parameters.AddWithValue("#AgeSql", playerAge.Text);
try
{
cmd.ExecuteNonQuery();
listView1.Items.Clear();
}
catch (Exception ex)
{
MessageBox.Show("Error:" + ex.Message);
dbCon.Connection.Close();
}
finally
{
updateListView();
}
}
}
What would be the best way for me to solve this problem and in the future be sure to close my connections properly?
UPDATE: (per request, included DB_connect)
class DB_connect
{
private DB_connect()
{
}
private string databaseName = "simhopp";
public string DatabaseName
{
get { return databaseName; }
set { databaseName = value; }
}
public string Password { get; set; }
private MySqlConnection connection = null;
public MySqlConnection Connection
{
get { return connection; }
}
private static DB_connect _instance = null;
public static DB_connect Instance()
{
if (_instance == null)
_instance = new DB_connect();
return _instance;
}
public bool IsConnect()
{
bool result = true;
try
{
if (Connection == null)
{
if (String.IsNullOrEmpty(databaseName))
result = false;
string connstring = string.Format("Server=localhost; database={0}; UID=root;", databaseName);
connection = new MySqlConnection(connstring);
connection.Open();
result = true;
}
}
catch (Exception ex)
{
Console.Write("Error: " + ex.Message);
}
return result;
}
public void Close()
{
connection.Close();
}
}
}
You are trying to have multiple open readers on the same connection. This is commonly called "MARS" (multiple active result sets). MySql seems to have no support for it.
You will have to either limit yourself to one open reader at a time, or use more than one connection, so you can have one connection for each reader.
My suggestion would be to throw away that singleton-like thingy and instead use connection pooling and proper using blocks.
As suggested by Pikoh in the comments, using the using clause indeed solved it for me.
Working code-snippet:
getLastIdFromDB
using (MySqlDataReader reader2 = cmd2.ExecuteReader()) {
while (reader2.Read())
{
string item = reader2["ID"].ToString();
lastIndex = int.Parse(item);
lastIndex++;
lastID = lastIndex.ToString();
}
}
Your connection handling here is not good. You need to ditch the DB_connect. No need to maintain a single connection - just open and close the connection each time you need it. Under the covers, ADO.NET will "pool" the connection for you, so that you don't actually have to wait to reconnect.
For any object that implements IDisposable you need to either call .Dispose() on it in a finally block, or wrap it in a using statement. That ensures your resources are properly disposed of. I recommend the using statement, because it helps keep the scope clear.
Your naming conventions should conform to C# standards. Methods that return a boolean should be like IsConnected, not IsConnect. addPlayerBtn_Click should be AddPlayerButton_Click. getLastIdFromDB should be GetlastIdFromDb or getLastIdFromDatabase.
public string GetLastIdFromDatabase()
{
int lastIndex;
string lastID ="";
using (var connection = new MySqlConnection(Configuration.ConnectionString))
using (var command = new MySqlCommand("query", connection))
{
connection.Open();
MySqlDataReader reader = cmd2.ExecuteReader();
while (reader.Read())
{
string item = reader2["ID"].ToString();
lastIndex = int.Parse(item);
lastIndex++;
lastID = lastIndex.ToString();
}
}
return lastID;
}
Note, your query is bad too. I suspect you're using a string data type instead of a number, even though your ID's are number based. You should switch your column to a number data type, then select the max() number. Or use an autoincrementing column or sequence to get the next ID. Reading every single row to determine the next ID and incrementing a counter not good.
Alright I originally started out using a Convert.ToInt32(myradTextBox.Text) then it said specified cast is not valid. I did some research on here and decided to try Int.TryParse. Upon doing so I still received this error. What I am trying to do is when the user enters an ID and hits the create button, it searches the DB to see if that ID is already there. I have also tried to convert the bool value from my Int.TryParse to int using Convert.ToInt32(Result) still same error (see below in third code post for where that would be posted). Maybe it has something to do with my comparison method.
Below I have provided the Int.TryParse method with values. The Method I am calling to check the userinput is not in the db currently and my if statement that is catching the statement. Any input on how to fix this would be greatly appreciated. I am still new to most of this stuff so I apologize if leaving any critical info off. Just ask if you need clarification or something elaborated.
Here is my method for comparison:
public bool isValidID(int id)
{
SqlConnection dbConn = null;
int count = 0;
try
{
using (dbConn = new SqlConnection(Properties.Settings.Default["tville"].ToString()))
{
string sql = "SELECT Count(*) FROM PackLabelFormat where PackFormatID = #PackFormatID";
SqlCommand cmd = dbConn.CreateCommand();
cmd.CommandText = sql;
cmd.Parameters.AddWithValue("#PackFormatID", id);
dbConn.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{
reader.Read();
count = reader.GetInt16(0);
}
}
}
catch (Exception ex)
{
throw ex;
}
if (count > 0)
return false;
return true;
}
Here is my variables that I use in my Int.TryParse method:
string IDselect = rTxtBoxFormatID.Text.ToString();
int resultInt;
bool result = int.TryParse(IDselect, out resultInt);
Lastly here is my method that is catching the error:
SqlConnection dbConn = null;
LabelData labelList = new LabelData();
try
{
using (dbConn = new SqlConnection(Properties.Settings.Default["tville"].ToString()))
{
if (SelectedVersion.isValidID(resultInt))
{
SelectedVersion.PackFormatID = resultInt;
}
else
{
MessageBox.Show("ID already in use!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
catch (Exception ex)
{
throw ex;
}
The database column did not support Int16 aka short. Which was why my specified cast is not valid error never went away no matter what I tried. Thank you for your help in this matter! Here is the code to further illustrate what the problem was.
using (SqlDataReader reader = cmd.ExecuteReader())
{
reader.Read();
//count = reader.GetInt16(0); needs to be reader.GetInt32(0);
}
I've written a small console app that I point to a folder containing DBF/FoxPo files.
It then creates a table in SQL based on each dbf table, then does a bulk copy to insert the data into SQL. It works quite well for the most part, except for a few snags..
1) Some of the FoxPro tables contain 5000000+ records and the connection expries before the insert completes..
Here is my connection string:
<add name="SQL" connectionString="data source=source_source;persist security info=True;user id=DBFToSQL;password=DBFToSQL;Connection Timeout=20000;Max Pool Size=200" providerName="System.Data.SqlClient" />
Error message:
"Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding."
CODE:
using (SqlConnection SQLConn = new SqlConnection(SQLString))
using (OleDbConnection FPConn = new OleDbConnection(FoxString))
{
ServerConnection srvConn = new Microsoft.SqlServer.Management.Common.ServerConnection(SQLConn);
try
{
FPConn.Open();
string dataString = String.Format("Select * from {0}", tableName);
using (OleDbCommand Command = new OleDbCommand(dataString, FPConn))
using (OleDbDataReader Reader = Command.ExecuteReader(CommandBehavior.SequentialAccess))
{
tbl = new Table(database, tableName, "schema");
for (int i = 0; i < Reader.FieldCount; i++)
{
col = new Column(tbl, Reader.GetName(i), ConvertTypeToDataType(Reader.GetFieldType(i)));
col.Nullable = true;
tbl.Columns.Add(col);
}
tbl.Create();
BulkCopy(Reader, tableName);
}
}
catch (Exception ex)
{
// LogText(ex, #"C:\LoadTable_Errors.txt", tableName);
throw ex;
}
finally
{
SQLConn.Close();
srvConn.Disconnect();
}
}
private DataType ConvertTypeToDataType(Type type)
{
switch (type.ToString())
{
case "System.Decimal":
return DataType.Decimal(18, 38);
case "System.String":
return DataType.NVarCharMax;
case "System.Int32":
return DataType.Int;
case "System.DateTime":
return DataType.DateTime;
case "System.Boolean":
return DataType.Bit;
default:
throw new NotImplementedException("ConvertTypeToDataType Not implemented for type : " + type.ToString());
}
}
private void BulkCopy(OleDbDataReader reader, string tableName)
{
using (SqlConnection SQLConn = new SqlConnection(SQLString))
{
SQLConn.Open();
SqlBulkCopy bulkCopy = new SqlBulkCopy(SQLConn);
bulkCopy.DestinationTableName = "schema." + tableName;
try
{
bulkCopy.WriteToServer(reader);
}
catch (Exception ex)
{
//LogText(ex, #"C:\BulkCopy_Errors.txt", tableName);
}
finally
{
SQLConn.Close();
reader.Close();
}
}
}
My 2nd & 3rd errors are the following:
I understand what the issues are, but how to rectify them i'm not so sure
2) "The provider could not determine the Decimal value. For example, the row was just created, the default for the Decimal column was not available, and the consumer had not yet set a new Decimal value."
3) SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.
I found a result on google that indicated what the issue is : [A]... and a possible work around [B] (but I'd like to keep my decimal values as decimal, and dates as date, as I'll be doing further calculations against the data)
What I'm wanting to do as a solution
1.) Either increase the connection time, (but i dont think i can increase it any more than i have), or alternatively is it possible to split the OleDbDataReader's results and do in incremental bulk insert?
2.)I was thinking if its possible to have bulk copy to ignore results with errors, or have the records that do error out log to a csv file or something to that extent?
So where you do the "for" statement I would probably break it up to take so many at a time :
int i = 0;
int MaxCount = 1000;
while (i < Reader.FieldCount)
{
var tbl = new Table(database, tableName, "schema");
for (int j = i; j < MaxCount; j++)
{
col = new Column(tbl, Reader.GetName(j), ConvertTypeToDataType(Reader.GetFieldType(j)));
col.Nullable = true;
tbl.Columns.Add(col);
i++;
}
tbl.Create();
BulkCopy(Reader, tableName);
}
So, "i" keeps track of the overall count, "j" keeps track of the incremental count (ie your max at one time count) and when you have created your 'batch', you create the table and Bulk Copy it.
Does that look like what you would expect?
Cheers,
Chris.
This is my current attemt at the bulk copy method, I't works for about 90% of the tables, but i get an OutOfMemory exeption, with the bigger tables... I'd like to split the reader's data into smaller secions, without having to pass it into a DataTable and store it in memory first (which is the cause of the OutOfMemory exception on the bigger result sets)
UPDATE
Imodified the code below as to how it looks in my solution.. It aint pretty.. but it works. I'll def do some refactoring, and update my answer again.
private void BulkCopy(OleDbDataReader reader, string tableName, Table table)
{
Console.WriteLine(tableName + " BulkCopy Started.");
try
{
DataTable tbl = new DataTable();
List<Type> typeList = new List<Type>();
foreach (Column col in table.Columns)
{
tbl.Columns.Add(col.Name, ConvertDataTypeToType(col.DataType));
typeList.Add(ConvertDataTypeToType(col.DataType));
}
int batch = 1;
int counter = 0;
DataRow tblRow = tbl.NewRow();
while (reader.Read())
{
counter++;
int colcounter = 0;
foreach (Column col in table.Columns)
{
try
{
tblRow[colcounter] = reader[colcounter];
}
catch (Exception)
{
tblRow[colcounter] = GetDefault(typeList[0]);
}
colcounter++;
}
tbl.LoadDataRow(tblRow.ItemArray, true);
if (counter == BulkInsertIncrement)
{
Console.WriteLine(tableName + " :: Batch >> " + batch);
counter = PerformInsert(tableName, tbl, batch);
batch++;
}
}
if (counter > 0)
{
Console.WriteLine(tableName + " :: Batch >> " + batch);
PerformInsert(tableName, tbl, counter);
}
tbl = null;
Console.WriteLine("BulkCopy Success!");
}
catch (Exception ex)
{
Console.WriteLine("BulkCopy Fail!");
SharedLogger.Write(ex, #"C:\BulkCopy_Errors.txt", tableName);
Console.WriteLine(ex.Message);
}
finally
{
reader.Close();
reader.Dispose();
}
Console.WriteLine(tableName + " BulkCopy Ended.");
Console.WriteLine("*****");
Console.WriteLine("");
}