nested data reader issue mysql c# - c#

I have written a custom class to handle database queries to a remote and local MySQL database, however when I do a nested loop I receive the below error:
MySql.Data.MySqlClient.MySqlException was unhandled
Message=There is already an open DataReader associated with this Connection which must be closed first.
Source=MySql.Data
ErrorCode=-2147467259
Number=0
My class currently looks like this
public class MySQLManager
{
private MySqlConnection _MySQLRemoteConnection { get; set; }
public void setup(string remoteUser, string remotePass, string remoteServerAddress, string remoteDb, string localUser, string localPass, string localServerAddress, string localDb)
{
_remote_server_address = remoteServerAddress;
_remote_database = remoteDb;
_remote_username = remoteUser;
_remote_password = remotePass;
}
public void connect()
{
try
{
_MySQLRemoteConnection = new MySqlConnection() { ConnectionString = string.Format("server={0};database={1};uid={2};password={3};", _remote_server_address, _remote_database, _remote_username, _remote_password) };
_MySQLRemoteConnection.Open();
_RemoteConnection = true;
}
catch (MySqlException ex)
{
_RemoteConnection = false;
}
}
public MySqlCommand run(string query, List<MySqlParameter> dbparams = null)
{
connect();
MySqlCommand sql = getConnection().CreateCommand();
sql.CommandText = query;
if (dbparams != null)
{
if (dbparams.Count > 0)
{
sql.Parameters.AddRange(dbparams.ToArray());
}
}
//disconnect();
return sql;
}
public MySqlDataReader fetch(MySqlCommand cmd)
{
//connect();
var t = cmd.ExecuteReader();
//disconnect();
return t;
}
And the code that I'm running to create the error, now I understand I can do the below example in a single query, this is an EXAMPLE query to re-create the error, writing it into a single query will not work with live examples.
query = "SELECT field1 FROM tmp WHERE field1 < 3";
using (var sql = db.run(query))
{
txtResponse.Text += "Query ran" + nl;
using (var row = db.fetch(sql))
{
txtResponse.Text += "Query fetched" + nl;
db.connect();
while (row.Read())
{
txtResponse.Text += "Row : " + row[0].ToString() + nl;
query = "SELECT val1 FROM tmp2 WHERE field1 = '" + row[0].ToString() + "'";
//db.disconnect();
using (var sql2 = db.run(query))
{
txtResponse.Text += "Query ran" + nl;
db.disconnect();
using (var row2 = db.fetch(sql))
{
txtResponse.Text += "Query fetched" + nl;
db.connect();
while (row.Read())
{
txtResponse.Text += " Val : " + row2[0].ToString() + nl;
}
}
}
}
}
}
So how would I go about getting the second loop to work?

For SQL Server, you could use MultipleActiveResultSets=true on connection string, but this most likely won't work for MySQL.
The other option is to use 2 connections, one for each data reader.

Related

SQL Server & C# : not returning any results [duplicate]

This question already has answers here:
C# SqlCommand - cannot use parameters for column names, how to resolve?
(2 answers)
Closed 5 years ago.
private void searchMulti(string searchType, string searchTerm)
{
{
{
var query = "";
cb_Surname.Items.Clear();
txt_patient_search.Clear();
if (patient_NHSID.Equals(null) != true)
{
pbar_search.Value = 2;
var connectionString = Settings.Default.CMTA_DBConnectionString;
using (var con = new SqlConnection(connectionString))
{
if (searchType != "NHSID")
{
query = #"SELECT * FROM Patient WHERE #p2 = '#p1' ";
}
else
{
query = #"SELECT * FROM Patient WHERE #p2 = #p1";
}
using (var qry_search = new SqlCommand(query))
{
qry_search.Connection = con;
qry_search.Parameters.Add("#p1", SqlDbType.VarChar).Value = searchTerm;
qry_search.Parameters.Add("#p2", SqlDbType.VarChar).Value = searchType;
con.Open();
qry_search.ExecuteNonQuery();
int firstIteration = 0;
using (var rdr = qry_search.ExecuteReader())
{
if (rdr.HasRows)
{
//Found Valid Patient Event
pbar_search.Value = 6;
pbox_tick.Show();
foundValidPatient = true;
////////////////////////////
while (rdr.Read())
{
if (firstIteration == 0)
{
pbar_search.Value = 8;
cb_Surname.Text = rdr.GetInt64(0) + " - " + rdr.GetString(1) + " - " +
rdr.GetString(2);
firstIteration = 1;
}
cb_Surname.Items.Add(rdr.GetInt64(0) + " - " + rdr.GetString(1) + " - " +
rdr.GetString(2));
}
}
else
{
//Patient Not Found
pbox_cross.Show();
patientSelected = false;
foundValidPatient = false;
}
con.Close();
}
}
}
}
else
{
MessageBox.Show("Please Enter Valid Text");
pbar_search.Value = 0;
pbox_cross.Show();
}
}
}
}
The method above isn't working. It should query the SQL Server database for a user entered term (such as textbox value) and query it for a searchtype (firstname) however when debugging the SQL query is executed but no rows are returned.
If I run the command without the parameters and insert actual values i.e (WHERE FirstName = 'Alan') it works perfectly.
What have I done incorrectly with this SQL query?
query = #"SELECT * FROM Patient WHERE #p2 = '#p1' ";
Many thanks!
Wrong: query = #"SELECT * FROM Patient WHERE #p2 = '#p1' ";
(Answer) Right: query = #"SELECT * FROM Patient WHERE " + searchType +" = #p1";
Answered by : – Tetsuya Yamamoto
You can't pass a column name in as a parameter, but what you can do is add it to your query string explicitly. You also might consider putting square brackets around the column name in case someone has a column name that is also a SQL keyword.
I have two examples of formatting a string with your column name in [] below:
if (searchType != "NHSID")
{
query = $#"SELECT * FROM Patient WHERE [{searchType}] = '#p1'";
}
else
{
query = string.Format(#"SELECT * FROM Patient WHERE [{0}] = #p1", searchType);
}

file already in use exception after using dispose and SuppressFinalize on MS access File

I am working on software that make changes in database through GUI. I want to compact database after user clicks save. After save user can continue to use software or close, so I am not using "using". I have created databaseAccess object which holds OleDbConnection connection object with few others. This is my database access class.
using System;
using System.Collections.Generic;
using System.Data.OleDb;
using System.Data;
using System.Diagnostics;
using System.Windows.Forms;
namespace TreeTool
{
public class DataBaseAccess
{
#region Properties
private string m_directory;
public List<string> selectedTableNames;
private Dictionary<String, DataTable> selectedTables;
private OleDbConnection mdbConnection;
DataTable dataTable;
//Constructor
public DataBaseAccess()
{
selectedTableNames = new List<string>();
selectedTables = new Dictionary<string, DataTable>();
}
public string directory
{
get
{
return m_directory;
}
set
{
m_directory = value;
}
}
#endregion
public List<string> GetAllTableNames()
{
if (dataTable != null)
{
List<string> tableList = new List<string>();
for (int i = 0; i < dataTable.Rows.Count; i++)
{
string TableName = dataTable.Rows[i][2].ToString();
tableList.Add(TableName);
}
return tableList;
}
return null;
}
/// <summary>
/// Returns Table Columns
/// </summary>
/// <returns></returns>
public DataTable GetTable(string TableName)
{
DataTable mdbTable;
if (selectedTables.TryGetValue(TableName, out mdbTable))
{
return mdbTable;
}
else
{
mdbTable = new DataTable();
//mdbConnection.Open();
string mdbCommandString = "SELECT * FROM [" + TableName + "]";
OleDbDataAdapter QueryCommand = new OleDbDataAdapter(mdbCommandString, mdbConnection);
QueryCommand.Fill(mdbTable);
//mdbConnection.Close();
selectedTables.Add(TableName, mdbTable);
return mdbTable;
}
}
public void SetTable(String TableName, DataTable dataTable)
{
//mdbConnection.Open();
OleDbCommand ac = new OleDbCommand("delete from [" + TableName + "]", mdbConnection);
ac.ExecuteNonQuery();
foreach (DataRow row in dataTable.Rows)
{
String query = "INSERT INTO [" + TableName + "] (TaskID, HTMLTopic, nRelative, [Group], nKey,"
+ " [nText], nImage, nSelImage, nFontName, nFontInfo, Keywords) VALUES (#TaskID,"
+ " #HTMLTopic, #nRelative, #Group, #nKey, #nText, #nImage, #nSelImage, #nFontName, "
+ " #nFontInfo, #Keywords)";
OleDbCommand command = new OleDbCommand(query, mdbConnection);
command.Parameters.AddWithValue("#TaskID", row["TaskID"]);
command.Parameters.AddWithValue("#HTMLTopic", row["HTMLTopic"]);
command.Parameters.AddWithValue("#nRelative", row["nRelative"]);
command.Parameters.AddWithValue("#Group", row["Group"]);
command.Parameters.AddWithValue("#nKey", row["nKey"]);
command.Parameters.AddWithValue("#nText", row["nText"]);
command.Parameters.AddWithValue("#nImage", row["nImage"]);
command.Parameters.AddWithValue("#nSelImage", row["nSelImage"]);
command.Parameters.AddWithValue("#nFontName", row["nFontName"]);
command.Parameters.AddWithValue("#nFontInfo", row["nFontInfo"]);
command.Parameters.AddWithValue("#Keywords", row["Keywords"]);
command.ExecuteNonQuery();
}
//mdbConnection.Close();
}
internal bool validTable(string TableName)
{
DataTable mdbTable = new DataTable();
//mdbConnection.Open();
string mdbCommandString = "SELECT * FROM [" + TableName + "]";
OleDbDataAdapter QueryCommand = new OleDbDataAdapter(mdbCommandString, mdbConnection);
QueryCommand.Fill(mdbTable);
//mdbConnection.Close();
// check if table contains all columns necessary
String[] columnNames = new string[] { "TaskID" , "HTMLTopic", "nRelative", "Group", "nKey",
"nText", "nImage", "nSelImage", "nFontName", "nFontInfo", "Keywords"};
Boolean missingColumn = false;
DataColumnCollection columns = mdbTable.Columns;
foreach (String columnName in columnNames)
{
if (columns.Contains(columnName) == false)
{
// print the message
MessageBox.Show("Database: " + directory + " Table: " + TableName + " is missing column \"" + columnName
+ "\". Add it to make changes.",
"Missing column",
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation,
MessageBoxDefaultButton.Button1);
missingColumn = true;
}
}
if (missingColumn == true)
{
return false;
}
return true;
}
public void insertTable(String tableName)
{
selectedTableNames.Add(tableName);
}
public List<String> getSelectedTables()
{
return selectedTableNames;
}
public Boolean isConnected()
{
if (mdbConnection == null)
{
return false;
}
return true;
}
public void connect()
{
if (mdbConnection == null)
{
String m_mdbDirectory = #"Provider=Microsoft.JET.OLEDB.4.0;Data Source=" + m_directory;
mdbConnection = new OleDbConnection(m_mdbDirectory);
mdbConnection.Open();
string[] restrictions = new string[4];
restrictions[3] = "Table";
dataTable = mdbConnection.GetSchema("TABLES", restrictions);
//mdbConnection.Close();
}
}
public void disconnect()
{
mdbConnection.Close();
mdbConnection.Dispose();
GC.SuppressFinalize(mdbConnection);
mdbConnection = null;
}
public void clearSelectedTables()
{
selectedTableNames.Clear();
}
}
}
Save and compact functions are like this
private void save()
{
foreach(DataBaseAccess database in databases)
{
// save changes code
database.disconnect();
CompactAndRepairAccessDB(database.directory);
database.connect();
}
}
private void CompactAndRepairAccessDB(string accessFile)
{
string tempFile = #"temp.mdb";
FileInfo temp = new FileInfo(tempFile);
// Required COM reference for project:
// Microsoft Office 14.0 Access Database Engine Object Library
var dbe = new Microsoft.Office.Interop.Access.Dao.DBEngine();
try
{
dbe.CompactDatabase(accessFile, tempFile);
temp.CopyTo(accessFile, true);
temp.Delete();
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message);
}
}
The exception happens on line "dbe.CompactDatabase(accessFile, tempFile);".
In the code in all the methods where you use OleDbDataAdapter and OleDbCommand make sure to use the using-Pattern on these objects. They can keep the mdb file open even though the actual connection is already disposed.
Methods that require modification seem to be GetTable, SetTable and ValidTable.

How can i call a Oracle connection method in C# with paramaters?

i have created a program in C# which inserts data into an Oracle database. It is pretty procedural though and i want to improve my program (and my knowledge) to use classes. I am having some trouble around calling a method with parameters. This is my code:
public class Oracle {
public void Insert() {
string oracleConnectionString = "User Id=" + l_orauser + "; Password=" + l_orapass + "; Data Source=" + l_oradb;
using (OracleConnection oracleConnection = new OracleConnection(oracleConnectionString)) {
oracleConnection.Open();
OracleGlobalization oracleSession = oracleConnection.GetSessionInfo();
oracleSession.DateFormat = "dd-mm-yyyy hh24:mi:ss";
oracleConnection.SetSessionInfo(oracleSession);
OracleTransaction oracleTransaction = oracleConnection.BeginTransaction();
OracleCommand oracleCommand = oracleConnection.CreateCommand();
oracleCommand.Transaction = oracleTransaction;
oracleCommand.CommandType = CommandType.Text;
string oracleCommandText = "insert into T1 (C1, C2, C3) values (:l_c1, :l_c2, :l_c3)";
oracleCommand.CommandText = oracleCommandText;
oracleCommand.BindByName = true;
oracleCommand.Parameters.Add("l_c1", OracleDbType.Byte, 3).Value = l_c1;
oracleCommand.Parameters.Add("l_c2", OracleDbType.Date).Value = l_c2;
oracleCommand.Parameters.Add("l_c3", OracleDbType.Varchar2, 1024).Value = l_c3;
try {
oracleCommand.ExecuteNonQuery();
oracleTransaction.Commit();
}
catch (Exception ex) {
oracleTransaction.Rollback();
MessageBox.Show(ex.Message);
}
finally {
oracleCommand.Parameters.Clear();
oracleCommand.Dispose();
oracleTransaction.Dispose();
oracleConnection.Close();
oracleConnection.Dispose();
}
}
}
}
I want to call this with some parameters - the variables: l_orauser, l_orapass, l_oradb, l_c1, l_c2, l_c3, which are taken from the elements of the form, for instance textbox, datetimepicker. How can i do that?
public static void Main(string[] args) {
var testOracle = new Oracle();
testOracle.Insert();
}
ok, so after discussing with Tim Freese i have decided to use constructors and an array of prameters.
For reference i have added the code, maybe somebody will find it useful:
public static void Main(string[] args) {
string oracleUser, oraclePassword, oracleDatabase;
List<string> oracleArguments = new List<string>();
//0 = oracleUser
//1 = oraclePassword
//2 = oracleDatabase
//3 = oracleCommandText
//4+ = oracleCommand.Parameters
l_orauser = "schema1";
l_orapass = "schema1pass";
l_oradb = "db1";
oracleArguments.Add(l_orauser);
oracleArguments.Add(l_orapass);
oracleArguments.Add(l_oradb);
Oracle testOracle = new Oracle();
testOracle.Insert(oracleArguments);
}
And the Oracle class:
public class Oracle {
public void Insert(List<string> oracleArguments) {
string oracleConnectionString = "User Id=" + oracleArguments[0] + "; Password=" + oracleArguments[1] + "; Data Source=" + oracleArguments[2];
using (OracleConnection oracleConnection = new OracleConnection(oracleConnectionString)) {
//do something
}
}
}

Is it safe to access SQL Server CE from multiple threads?

I have a large CSV database of about 5MB with ZIP codes, cities, and states that I'm trying to import into a SQL Server CE database.
Using a single thread, the process is estimated to take about 3 hours to complete. While this is fine for getting the job done, I'd like to try and split up the task across multiple threads to cut down on the 3 hours total time. If I create a SqlCeConnection object on each thread, is it safe to run commands on each thread simultaneously?
I have a feeling that there would be issues with concurrency and deadlocks. Here is where I found the CSV database: http://www.unitedstateszipcodes.org/zip-code-database/
Here is my relevant code:
List<AddressSet> addressList;
public void OpenCSV(string file)
{
var addresses = from line in File.ReadAllLines(file).Skip(1)
let columns = line.Split(',')
select new AddressSet
{
ZipCode = columns[0].Replace("\"", "").Trim(),
City = columns[2].Replace("\"", "").Trim(),
State = columns[5].Replace("\"", "").Trim()
};
addressList = addresses.ToList();
Thread worker = new Thread(new ThreadStart(ProcessData));
worker.Start();
}
private void ProcessData()
{
try
{
int i = 1;
DateTime operationStart = DateTime.Now;
foreach (AddressSet address in addressList)
{
int stateId = InsertState(address.State);
int zipCodeId = InsertZipCode(address.ZipCode, stateId);
int cityId = InsertCity(address.City, stateId);
UpdateRelationships(zipCodeId, cityId);
float pct = i / (float)addressList.Count() * 100;
TimeSpan timeSinceStart = DateTime.Now.Subtract(operationStart);
TimeSpan totalTime = TimeSpan.FromMilliseconds(timeSinceStart.TotalMilliseconds / (pct/100));
TimeSpan timeLeft = totalTime - timeSinceStart;
//richTextBox1.BeginInvoke((MethodInvoker)(() => richTextBox1.Text = pct.ToString("N2") + "% (" + i + " of " + addressList.Count().ToString() + ") " + address.City + ", " + address.State + " " + address.ZipCode
// + "\nEstimated Total Time: " + totalTime.Days.ToString() + " days, " + totalTime.Hours.ToString() + " hours, " + totalTime.Minutes.ToString() + " minutes" +
// " - Time Left: " + timeLeft.Days.ToString() + " days, " + timeLeft.Hours.ToString() + " hours, " + timeLeft.Minutes.ToString() + " minutes"));
richTextBox1.BeginInvoke((MethodInvoker)(() => richTextBox1.Text = pct.ToString("N2") + "% (" + i + " of " + addressList.Count().ToString() + ") " + address.City + ", " + address.State + " " + address.ZipCode
+ "\nEstimated Total Time: " + totalTime.ToString("h'h 'm'm 's's'") +
"\nTime Left: " + timeLeft.ToString("h'h 'm'm 's's'") +
"\nRunning Time: " + timeSinceStart.ToString("h'h 'm'm 's's'")));
richTextBox1.BeginInvoke((MethodInvoker)(() => richTextBox1.SelectionStart = richTextBox1.Text.Length));
richTextBox1.BeginInvoke((MethodInvoker)(() => richTextBox1.ScrollToCaret()));
i++;
}
this.Invoke(new Action(() =>
{
MessageBox.Show("Done!");
btnChooseCSV.Enabled = true;
}));
}
catch (Exception ex)
{
this.Invoke(new Action(() =>
{
MessageBox.Show(ex.Message);
}));
}
}
private int InsertZipCode(string zipCode, int stateId)
{
string connstr = System.Configuration.ConfigurationManager.ConnectionStrings["AddressInformation"].ConnectionString;
SqlCeConnection connection = new SqlCeConnection(connstr);
connection.Open();
SqlCeCommand command = new SqlCeCommand("SELECT COUNT(*) FROM ZipCode WHERE ZipCode = #ZipCode", connection);
command.Parameters.AddWithValue("ZipCode", zipCode);
int result = (int)command.ExecuteScalar();
// if nothing found, insert
if (result == 0)
{
command = new SqlCeCommand("INSERT INTO ZipCode(ZipCode, StateId) VALUES(#ZipCode, #StateId)", connection);
command.Parameters.AddWithValue("ZipCode", zipCode);
command.Parameters.AddWithValue("StateId", stateId);
command.ExecuteNonQuery();
command = new SqlCeCommand("SELECT ##IDENTITY", connection);
}
if (result == 1)
{
command = new SqlCeCommand("SELECT ZipCodeId FROM ZipCode WHERE ZipCode = #ZipCode", connection);
command.Parameters.AddWithValue("ZipCode", zipCode);
}
string test = command.ExecuteScalar().ToString();
result = int.Parse(test);
connection.Close();
return result;
}
private int InsertCity(string city, int stateId)
{
string connstr = System.Configuration.ConfigurationManager.ConnectionStrings["AddressInformation"].ConnectionString;
SqlCeConnection connection = new SqlCeConnection(connstr);
connection.Open();
SqlCeCommand command = new SqlCeCommand("SELECT COUNT(*) FROM City WHERE CityName = #City", connection);
command.Parameters.AddWithValue("City", city);
int result = (int)command.ExecuteScalar();
// if nothing found, insert
if (result == 0)
{
command = new SqlCeCommand("INSERT INTO City(CityName, StateId) VALUES(#City, #StateId)", connection);
command.Parameters.AddWithValue("City", city);
command.Parameters.AddWithValue("StateId", stateId);
command.ExecuteNonQuery();
command = new SqlCeCommand("SELECT ##IDENTITY", connection);
}
if (result == 1)
{
command = new SqlCeCommand("SELECT CityId FROM City WHERE CityName = #City", connection);
command.Parameters.AddWithValue("City", city);
}
string test = command.ExecuteScalar().ToString();
result = int.Parse(test);
connection.Close();
return result;
}
private int InsertState(string state)
{
string connstr = System.Configuration.ConfigurationManager.ConnectionStrings["AddressInformation"].ConnectionString;
SqlCeConnection connection = new SqlCeConnection(connstr);
connection.Open();
SqlCeCommand command = new SqlCeCommand("SELECT COUNT(*) FROM State WHERE State = #State", connection);
command.Parameters.AddWithValue("State", state);
int result = (int)command.ExecuteScalar();
// if nothing found, insert
if (result == 0)
{
command = new SqlCeCommand("INSERT INTO State(State) VALUES(#State)", connection);
command.Parameters.AddWithValue("State", state);
command.ExecuteNonQuery();
command = new SqlCeCommand("SELECT ##IDENTITY", connection);
}
if (result == 1)
{
command = new SqlCeCommand("SELECT StateId FROM State WHERE State = #State", connection);
command.Parameters.AddWithValue("State", state);
}
string test = command.ExecuteScalar().ToString();
result = int.Parse(test);
connection.Close();
return result;
}
private void UpdateRelationships(int zipCodeId, int cityId)
{
string connstr = System.Configuration.ConfigurationManager.ConnectionStrings["AddressInformation"].ConnectionString;
SqlCeConnection connection = new SqlCeConnection(connstr);
connection.Open();
SqlCeCommand command = new SqlCeCommand("INSERT INTO CityZipCode(CityId, ZipCodeId) VALUES(#CityId, #ZipCodeId)", connection);
command.Parameters.AddWithValue("CityId", cityId);
command.Parameters.AddWithValue("ZipCodeId", zipCodeId);
command.ExecuteNonQuery();
connection.Close();
}
Edit:
Just to clarify, I'm not just simply inserting each row of information from the CSV file. I'm changing how the data is laid out by inserting each respective item into separate tables and adding relationships between each entity.
For example, a city can have multiple zip codes and a zip code can sometimes cover multiple cities so that would be represented by a many to many relationship. Cities and zip codes have only one state so that relationship is many to one.
I have a table for cities, zip codes, and states. I also have a table for relating cities to zip codes. I will need to modify my relationship table schema to take into effect that cities with the same name may exist in multiple states. The relationship table should really be a set including the city, state and zip code and not just the city and zip code.
My end goal is to distribute the SQL Server CE database with password protection with another application for city, state and zip code validation. I don't want to distribute the CSV database as anyone could change that to pass validation.
You must create a connection object per thread, it is not safe for multithreading:
SqlCeConnection Class
Edited
SQL CE objects are not thread-safe and are not thread affinitive
either. If an instance of SqlCeConnection or SqlCeTransaction is
shared across threads without ensuring thread safety, then that may
lead to Access Violation exception.
It is recommended that each thread should use a separate connection
than sharing across. If there is really a need for sharing SQL CE
objects across threads, then the application should serialize access
to these objects.
Multithreaded programming with SQL Server Compact
Why you don't use SQL Server Compact Toolbox You can use it, which generates INSERT statements based on a CSV file.
or use Conversion of CSV to SQLCE database app
Just a suggestion, I am doing the same kind of thing, and this is what I have, it is extremely fast compared to the simple solution
public static DataTable CSVToDataTable(string path, string name)
{
return CSVToDataTable(Path.Combine(path, name));
}
public static DataTable CSVToDataTable(string path)
{
DataTable res = new DataTable();
if (!File.Exists(path))
{
return res;
}
using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (StreamReader re = new StreamReader(stream))
{
if (re.EndOfStream)
return res;
string line = re.ReadLine();
if (line.IsNullOrWhiteSpace())
return res;
string[] headers = LineToArray(line);
foreach (string header in headers)
{
res.Columns.Add(header);
}
int i = 0;
string[] cells = new string[0];
DataRow row = null;
while (!re.EndOfStream)
{
line = re.ReadLine();
if (line.IsNullOrWhiteSpace())
continue;
cells = LineToArray(line);
row = res.NewRow();
for (i = 0; i < headers.Length && i < cells.Length; i += 1)
{
row[i] = cells[i];
}
res.Rows.Add(row);
}
}
}
return res;
}
private static string[] LineToArray(string line, char delimiter = ',')
{
if (line.Contains("\""))
{
List<string> l = new List<string>();
bool inq = false;
string cell = string.Empty;
char lastCh = 'x';
foreach (char ch in line)
{
if (ch == '"')
{
if (cell.Length == 0)
{
inq = true;
}
else if (lastCh == '\\')
{
cell += ch;
}
else
{
inq = false;
}
}
else if (delimiter == ch)
{
if (inq)
{
cell += ch;
}
else
{
l.Add(cell);
inq = false;
cell = string.Empty;
}
}
else
{
cell += ch;
}
if (inq)
lastCh = ch;
else
lastCh = 'x';
}
return l.ToArray();
}
else
{
return line.Split(new String[] { delimiter.ToString() }, StringSplitOptions.None);
}
}
public void insert(string path, string name, string table, bool KeepNulls){
DataTable data = CSVToDataTable(path, name);
//do data manipulation here
SqlCeBulkCopyOptions options = new SqlCeBulkCopyOptions();
if (KeepNulls)
{
options = options |= SqlCeBulkCopyOptions.KeepNulls;
}
using (SqlCeBulkCopy bc = new SqlCeBulkCopy(Fastway_Remote_Agent.Properties.Settings.Default.DatabaseConnectionString, options))
{
bc.DestinationTableName = table;
bc.WriteToServer(data);
}
}
Using this library: http://sqlcebulkcopy.codeplex.com/
Also for thread pooling (Change it to meet your needs):
/// <summary>
/// Manages open connections on a per-thread basis
/// </summary>
public abstract class SqlCeConnectionPool
{
private static Dictionary<int, DBCon> threadConnectionMap = new Dictionary<int, DBCon>();
private static Dictionary<int, Thread> threadMap = new Dictionary<int, Thread>();
/// <summary>
/// The connection map
/// </summary>
public static Dictionary<int, DBCon> ThreadConnectionMap
{
get { return SqlCeConnectionPool.threadConnectionMap; }
}
/// <summary>
/// Gets the connection string.
/// </summary>
/// <value>The connection string.</value>
public static ConnectionString ConnectionString
{
get { return global::ConnectionString.Default; }
}
/// <summary>
/// Gets a connection for this thread, maintains one open one of each.
/// </summary>
/// <remarks>Don't do this with anything but SQL compact edition or you'll run out of connections - compact edition is not
/// connection pooling friendly and unloads itself too often otherwise so that is why this class exists</remarks>
/// <returns>An open connection</returns>
public static DBCon Connection
{
get
{
lock (threadConnectionMap)
{
//do some quick maintenance on existing connections (closing those that have no thread)
List<int> removeItems = new List<int>();
foreach (var kvp in threadConnectionMap)
{
if (threadMap.ContainsKey(kvp.Key))
{
if (!threadMap[kvp.Key].IsAlive)
{
//close the connection
if (!kvp.Value.Disposed)
kvp.Value.Dispose();
removeItems.Add(kvp.Key);
}
}
else
{
if (!kvp.Value.Disposed)
kvp.Value.Dispose();
removeItems.Add(kvp.Key);
}
}
foreach (int i in removeItems)
{
threadMap.Remove(i);
threadConnectionMap.Remove(i);
}
//now issue the appropriate connection for our current thread
int threadId = Thread.CurrentThread.ManagedThreadId;
DBCon connection = null;
if (threadConnectionMap.ContainsKey(threadId))
{
connection = threadConnectionMap[threadId];
if (connection.Disposed)
{
if (threadConnectionMap.ContainsKey(threadId))
threadConnectionMap.Remove(threadId);
if (threadMap.ContainsKey(threadId))
threadMap.Remove(threadId);
connection = null;
}
else if (connection.Connection.State == ConnectionState.Broken)
{
connection.Dispose();
if (threadConnectionMap.ContainsKey(threadId))
threadConnectionMap.Remove(threadId);
if (threadMap.ContainsKey(threadId))
threadMap.Remove(threadId);
connection = null;
}
else if (connection.Connection.State == ConnectionState.Closed)
{
connection.Dispose();
if (threadConnectionMap.ContainsKey(threadId))
threadConnectionMap.Remove(threadId);
if (threadMap.ContainsKey(threadId))
threadMap.Remove(threadId);
connection = null;
}
}
if (connection == null)
{
connection = new DBCon(ConnectionString);
//connection.Connection.Open();
if (threadConnectionMap.ContainsKey(threadId))
threadConnectionMap[threadId] = connection;
else
threadConnectionMap.Add(threadId, connection);
if (threadMap.ContainsKey(threadId))
threadMap[threadId] = Thread.CurrentThread;
else
threadMap.Add(threadId, Thread.CurrentThread);
}
return connection;
}
}
}
}

SQL Syntax Error (INSERT command)

I have a form with a text box and button, such that when the user clicks the button, the specified name in the text box is added to a table in my sql database. The code for the button is as follows:
private void btnAddDiaryItem_Click(object sender, EventArgs e)
{
try
{
string strNewDiaryItem = txtAddDiaryItem.Text;
if (strNewDiaryItem.Length == 0)
{
MessageBox.Show("You have not specified the name of a new Diary Item");
return;
}
string sqlText = "INSERT INTO tblDiaryTypes (DiaryType) VALUES = ('" + strNewDiaryItem + "');";
cSqlQuery cS = new cSqlQuery(sqlText, "non query");
PopulateInitialDiaryItems();
MessageBox.Show("New Diary Item added succesfully");
}
catch (Exception ex)
{
MessageBox.Show("Unhandled Error: " + ex.Message);
}
}
The class cSqlQuery is a simple class that executes various T-SQL actions for me and its code is as follows:
class cSqlQuery
{
public string cSqlStat;
public DataTable cQueryResults;
public int cScalarResult;
public cSqlQuery()
{
this.cSqlStat = "empty";
}
public cSqlQuery(string paramSqlStat, string paramMode)
{
this.cSqlStat = paramSqlStat;
string strConnection = BuildConnectionString();
SqlConnection linkToDB = new SqlConnection(strConnection);
if (paramMode == "non query")
{
linkToDB.Open();
SqlCommand sqlCom = new SqlCommand(paramSqlStat, linkToDB);
sqlCom.ExecuteNonQuery();
linkToDB.Close();
}
if (paramMode == "table")
{
using (linkToDB)
using (var adapter = new SqlDataAdapter(cSqlStat, linkToDB))
{
DataTable table = new DataTable();
adapter.Fill(table);
this.cQueryResults = table;
}
}
if (paramMode == "scalar")
{
linkToDB.Open();
SqlCommand sqlCom = new SqlCommand(paramSqlStat, linkToDB);
this.cScalarResult = (Int32)sqlCom.ExecuteScalar();
linkToDB.Close();
}
}
public cSqlQuery(SqlCommand paramSqlCom, string paramMode)
{
string strConnection = BuildConnectionString();
SqlConnection linkToDB = new SqlConnection(strConnection);
paramSqlCom.Connection = linkToDB;
if (paramMode == "table")
{
using (linkToDB)
using (var adapter = new SqlDataAdapter(paramSqlCom))
{
DataTable table = new DataTable();
adapter.Fill(table);
this.cQueryResults = table;
}
}
if (paramMode == "scalar")
{
linkToDB.Open();
paramSqlCom.Connection = linkToDB;
this.cScalarResult = (Int32)paramSqlCom.ExecuteScalar();
linkToDB.Close();
}
}
public string BuildConnectionString()
{
cConnectionString cCS = new cConnectionString();
return cCS.strConnect;
}
}
The class works well throughout my application so I don't think the error is in the class, but then I can't be sure.
When I click the button I get the following error message:
Incorrect syntax near =
Which is really annoying me, because when I run the exact same command in SQL Management Studio it works fine.
I'm sure I'm missing something rather simple, but after reading my code through many times, I'm struggling to see where I have gone wrong.
you have to remove = after values.
string sqlText = "INSERT INTO tblDiaryTypes (DiaryType) VALUES ('" + strNewDiaryItem + "');"
and try to use Parameterized queries to avoid Sql injection. use your code like this. Sql Parameters
string sqlText = "INSERT INTO tblDiaryTypes (DiaryType) VALUES (#DairyItem);"
YourCOmmandObj.Parameters.AddwithValue("#DairyItem",strNewDiaryIItem)
Remove the = after VALUES.
You do not need the =
A valid insert would look like
INSERT INTO table_name (column1, column2, column3,...)
VALUES (value1, value2, value3,...)
Source: http://www.w3schools.com/sql/sql_insert.asp
Please use following:
insert into <table name> Values (value);
Remove "=", and also i would recommend you to use string.format() instead of string concatenation.
sqlText = string.format(INSERT INTO tblDiaryTypes (DiaryType) VALUES ('{0}'), strNewDiaryItem);"

Categories