Problems inserting items in a database using SQLite in C# - c#

i am trying to insert items in a database using SQLite but when i call loadfunction i receive an error like out of index. I think the problem is when i call add function. I checked parameters values and all seems to be ok, but the elements are not inserted in the table. Bellow you will see my table, add function and load function.
The table:
CREATE TABLE `Fisiere` (
`Nume` TEXT,
`Dimensiune` INTEGER,
`Data` BLOB,
`Rating_imdb` REAL,
`Cale` TEXT
);
The insert function:
public void addFisier(DirectorVideo[] directors)
{
var dbCommand = new SQLiteCommand();
dbCommand.Connection = _dbConnection;
dbCommand.CommandText = "insert into Fisiere(Nume, Dimensiune, Data, Rating_imdb, Cale) values(#nume, #dimensiune, #data, #rating_imdb, #cale);";
try {
_dbConnection.Open();
dbCommand.Transaction = _dbConnection.BeginTransaction();
for (int i = 0; i < directors.Length - 1; i++)
{
for (int j = 0; j < directors[i].nrFisiere; j++)
{
var numeParam = new SQLiteParameter("#nume");
numeParam.Value = directors[i].fisiere[j].numeFisier;
var dimensiuneParam = new SQLiteParameter("#dimensiune");
dimensiuneParam.Value = directors[i].fisiere[j].dimensiune;
var dataParam = new SQLiteParameter("#data");
dataParam.Value = directors[i].fisiere[j].data;
var ratingParam = new SQLiteParameter("rating_imdb");
IMDb rat = new IMDb(directors[i].fisiere[j].numeFisier);
ratingParam.Value = rat.Rating;
var caleParam = new SQLiteParameter("cale");
caleParam.Value = directors[i].cale;
Console.WriteLine(numeParam.Value);
dbCommand.Parameters.Add(numeParam);
dbCommand.Parameters.Add(dimensiuneParam);
dbCommand.Parameters.Add(dataParam);
dbCommand.Parameters.Add(ratingParam);
dbCommand.Parameters.Add(caleParam);
Console.WriteLine(caleParam.Value);
dbCommand.Transaction.Commit();
Console.WriteLine("A fost inserat");
}
}
}
catch (Exception)
{
Console.WriteLine("muie");
dbCommand.Transaction.Rollback();
throw;
}
finally
{
if (_dbConnection.State != ConnectionState.Closed) _dbConnection.Close();
}
}
Load file function
public void LoadFiles()
{
const string stringSql = "PRAGMA database_list";
try
{
_dbConnection.Open();
SQLiteCommand sqlCommand = new SQLiteCommand(stringSql, _dbConnection);
SQLiteDataReader sqlReader = sqlCommand.ExecuteReader();
try
{
while (sqlReader.Read())
{
Console.WriteLine("se afiseaza");
Console.WriteLine((long)sqlReader["Id_fisier"]);
Console.WriteLine((string)sqlReader["Nume"]);
Console.WriteLine((long)sqlReader["Dimensiune"]);
Console.WriteLine(DateTime.Parse((string)sqlReader["Data"]));
Console.WriteLine((long)sqlReader["Rating_imdb"]);
Console.WriteLine((string)sqlReader["Cale"]);
}
}
finally
{
// Always call Close when done reading.
sqlReader.Close();
}
}
finally
{
if (_dbConnection.State != ConnectionState.Closed) _dbConnection.Close();
}
}

You are going to need to Commit your transaction. You call BeginTransaction() but you never commit your transaction so the data never gets written to the DB. Check this out for the details and workflow with Transactions. https://www.sqlite.org/lang_transaction.html
The other problem is that your Transactions and your Commands are all out of order. You need to execute your commands within your transaction and then commit the transaction.
public void addFisier(DirectorVideo[] directors)
{
SQLiteTransaction dbTrans;
try
{
_dbConnection.Open();
// Start Transaction first.
dbTrans = _dbConnection.BeginTransaction();
for (int i = 0; i < directors.Length - 1; i++)
{
for (int j = 0; j < directors[i].nrFisiere; j++)
{
// Create commands that run based on your number of inserts.
var dbCommand = new SQLiteCommand();
dbCommand.Connection = _dbConnection;
dbCommand.CommandText = "insert into Fisiere(Nume, Dimensiune, Data, Rating_imdb, Cale) values(#nume, #dimensiune, #data, #rating_imdb, #cale);";
dbCommand.Transaction = dbTrans;
var numeParam = new SQLiteParameter("#nume");
numeParam.Value = directors[i].fisiere[j].numeFisier;
var dimensiuneParam = new SQLiteParameter("#dimensiune");
dimensiuneParam.Value = directors[i].fisiere[j].dimensiune;
var dataParam = new SQLiteParameter("#data");
dataParam.Value = directors[i].fisiere[j].data;
var ratingParam = new SQLiteParameter("rating_imdb");
IMDb rat = new IMDb(directors[i].fisiere[j].numeFisier);
ratingParam.Value = rat;
var caleParam = new SQLiteParameter("cale");
caleParam.Value = directors[i].cale;
Console.WriteLine(numeParam.Value);
dbCommand.Parameters.Add(numeParam);
dbCommand.Parameters.Add(dimensiuneParam);
dbCommand.Parameters.Add(dataParam);
dbCommand.Parameters.Add(ratingParam);
dbCommand.Parameters.Add(caleParam);
Console.WriteLine(caleParam.Value);
Console.WriteLine("A fost inserat");
// Actually execute the commands.
dbCommand.ExecuteNonQuery();
}
}
// If everything is good, commit the transaction.
dbTrans.Commit();
}
catch (Exception)
{
Console.WriteLine("muie");
dbTrans.Rollback();
throw;
}
finally
{
if (_dbConnection.State != ConnectionState.Closed) _dbConnection.Close();
}
}
Here is also a snippet from the SQLiteTransaction Class documentation. I suggest reading it: https://www.devart.com/dotconnect/sqlite/docs/Devart.Data.SQLite~Devart.Data.SQLite.SQLiteTransaction.html
public static void RunSQLiteTransaction(string myConnString) {
using (SQLiteConnection sqConnection = new SQLiteConnection(myConnString)) {
sqConnection.Open();
// Start a local transaction
SQLiteTransaction myTrans = sqConnection.BeginTransaction(System.Data.IsolationLevel.ReadCommitted);
SQLiteCommand sqCommand = sqConnection.CreateCommand();
try {
sqCommand.CommandText = "INSERT INTO Dept(DeptNo, DName) Values(52, 'DEVELOPMENT')";
sqCommand.ExecuteNonQuery();
sqCommand.CommandText = "INSERT INTO Dept(DeptNo, DName) Values(62, 'PRODUCTION')";
sqCommand.ExecuteNonQuery();
myTrans.Commit();
Console.WriteLine("Both records are written to database.");
}
catch (Exception e) {
myTrans.Rollback();
Console.WriteLine(e.ToString());
Console.WriteLine("Neither record was written to database.");
}
finally {
sqCommand.Dispose();
myTrans.Dispose();
}
}
}

Related

How to bulk update 1000 records using C#/SQL

I am reading from a table with a million records, I perform some modifications to some columns and I would like to save them back in bulk. I would like to perform a bulk update after every 10000 records.
I'm using .Net Core 3.1
My code :
public void FixText()
{
SqlConnection cnn = new SqlConnection(strConn);
string queryString = "SELECT ClientID, ServerName, Text FROM [dbo].[Client]";
SqlCommand selectCmd = new SqlCommand(queryString, cnn);
cnn.Open();
int j = 0;
SqlDataReader reader = selectCmd.ExecuteReader();
List<Client> clients = new List<Client>();
try
{
while (reader.Read())
{
j++;
ClientID = (int)reader["ClientID"];
ServerName = reader["ServerName"].ToString();
Text = reader["Text"].ToString();
//Modify Text & set ServerName
string Text = UpdateText(Text);
if text.StartWith("doo"){ServerName = "re";}
//perform bulk update
if (j > 10000)
{
Client client = new Client()
{
ClientID = (int)ClientID,
ServerName = ServerName,
Text = Text,
};
clients.Add(client);
//I'm struggling here on what to use to do a bulk update
j = 0;
}
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
reader.Close();
}
cnn.Close();
}
Any Help is appreciated!
You have two options, either use MERGE statement, or UPDATE.
I will do UPDATE option, as it's the easiest one. (This would need FastMember nuget).
private void ExecuteSql(SqlConnection connection , string sql , SqlParameter[] parameters = null)
{
if(connection == null)
{
throw new ArgumentNullException(nameof(connection));
}
if(string.IsNullOrWhiteSpace(sql))
{
throw new ArgumentNullException(nameof(sql));
}
using(var command = new SqlCommand(sql , connection))
{
if(parameters?.Length > 0)
{
command.Parameters.AddRange(parameters);
}
if(connection.State != ConnectionState.Open)
connection.Open();
command.ExecuteNonQuery();
}
}
private void ExecuteBulkCopy<T>(SqlConnection connection , IEnumerable<T> entries , string destinationTableName , string[] columns = null , int batchSize = 1000000)
{
if(connection == null)
{
throw new ArgumentNullException(nameof(connection));
}
if(entries == null)
{
throw new ArgumentNullException(nameof(entries));
}
if(string.IsNullOrWhiteSpace(destinationTableName))
{
throw new ArgumentNullException(nameof(destinationTableName));
}
if(connection.State != ConnectionState.Open)
connection.Open();
using(SqlBulkCopy sbc = new SqlBulkCopy(connection)
{
BulkCopyTimeout = 0 ,
DestinationTableName = destinationTableName ,
BatchSize = batchSize
})
{
using(var reader = ObjectReader.Create(entries , columns))
{
sbc.WriteToServer(reader);
}
}
}
private IEnumerable<Client> GetUpdatedClients(SqlConnection connection)
{
using(var command = new SqlCommand("SELECT ClientID, ServerName, Text FROM [dbo].[Client]", connection))
{
connection.Open();
using(SqlDataReader reader = _connection.ExecuteReader(query , parameters))
{
if(reader.HasRows)
{
while(reader.Read())
{
if(reader.IsDBNull(x)) { continue; }
var clientId = (int)reader["ClientID"];
var serverName = reader["ServerName"]?.ToString();
var text = reader["Text"]?.ToString();
//Modify Text & set ServerName
string textUpdated = UpdateText(text);
if(textUpdated.StartWith("doo"))
{
serverName = "re";
}
var client = new Client()
{
ClientID = clientId,
ServerName = serverName,
Text = textUpdated
};
yield return client;
}
}
}
}
}
private void BulkUpdateClients(SqlConnection connection, IEnumerable<Client> clients)
{
const string dropTempTable = "IF OBJECT_ID('[tempdb].[dbo].[##Client]') IS NOT NULL DROP TABLE [tempdb].[dbo].[##Client];";
// drop temp table if exists
ExecuteSql(connection ,dropTempTable);
// create the temp table
ExecuteSql($"SELECT TOP 1 [ClientID], [ServerName], [Text] INTO [tempdb].[dbo].[##Client] FROM [dbo].[Client];");
// copy rows to the temp table
ExecuteBulkCopy(connection, clients , "[tempdb].[dbo].[##Client]", new[] { "ClientID", "ServerName", "Text" });
// Use UPDATE JOIN
ExecuteSql("UPDATE t1 SET [ServerName] = t2.[ServerName], [Text] = t2.[Text] FROM [dbo].[Client] t1 JOIN [tempdb].[dbo].[##Client] t2 ON t1.[ClientID] = t2.[ClientID];");
// drop temp table
ExecuteSql(connection,dropTempTable);
}
public void BulkUpdateClients()
{
try
{
using(var connection = new SqlConnection(strConn))
{
connection.Open();
var clients = GetUpdatedClients(connection);
// it's important to use the same connection and keep it a live
// otherwise the temp table will be dropped.
BulkUpdate(connection, clients);
}
}
catch(Exception ex)
{
throw ex;
}
}
If you don't need to use temp table, you can change it to a permanent table (just change the temp table name).
To resolve this there are two ways.
You can use User-Defined Types or Sending array of record as JSON datatype through store procedure
UDT
OPENJSON

ProductInsert() does not exist in current context

protected void Btn_CheckOut_Click(object sender, EventArgs e)
{
int result = 0;
Payment user = new Payment(txt_CardNumber.Text, txt_CardHolderName.Text, txt_ExpirationDate.Text, txt_Cvv.Text);
result = ProductInsert();
/* Session["CardNumber"] = txt_CardNumber.Text;
Session["CardHolderName"] = txt_CardHolderName.Text;
Session["ExpirationDate"] = txt_ExpirationDate.Text;
Session["Cvv"] = txt_Cvv.Text;*/
Response.Redirect("Payment Sucessful.aspx");
}
public int ProductInsert()
{
int result = 0;
string queryStr = "INSERT INTO CustomerDetails(CardNumber, CardHolderName, ExpirationDate, Cvv)"
+ "values (#CardNumber,#CardHolderName, #ExpirationDate, #Cvv)";
try
{
SqlConnection conn = new SqlConnection(connStr);
SqlCommand cmd = new SqlCommand(queryStr, conn);
cmd.Parameters.AddWithValue("#CardNumber", this.CardNumber);
cmd.Parameters.AddWithValue("#CardHolderName", this.CardHolderName);
cmd.Parameters.AddWithValue("#ExpirationDate", this.ExpirationDate);
cmd.Parameters.AddWithValue("#Cvv", this.Cvv);
conn.Open();
result += cmd.ExecuteNonQuery(); // Returns no. of rows affected. Must be > 0
conn.Close();
return result;
}
catch (Exception ex)
{
return 0;
}
}
}
I am trying to store credit card informations into database. I have created a productInsert() method and now I am trying to insert whatever values into the database.
This code is giving the error:
ProductInsert() does not exist in current context

ConnectionStrings error c#

private void button2_Click(object sender, EventArgs e)
{
if (textBox1.Text != "")
{
try
{
con.ConnectionString = ConfigurationManager.ConnectionStrings["DeathWish"].ToString();
con.Open();
string query = string.Format("Select [ID],Decision from Data where [ID]='{0}' order by Decision", textBox1.Text);
SqlCommand cmd = new SqlCommand(query,con);
SqlDataReader dr = cmd.ExecuteReader();
string[] s = new string[] { };
while (dr.Read())
{
s = dr["Decision"].ToString().Split(',');
}
int length = s.Length;
for (int i = 0; i < length - 1; i++)
{
string fetr = s[i];
for (int j = 0; j <= checkedListBox1.Items.Count - 1; j++)
{
if (checkedListBox1.Items[j].ToString() == s[i])
{
checkedListBox1.SetItemChecked(j, true);
break;
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + ex.ToString());
}
}
string query = string.Format("Select [ID],Decision from Data where [ID]='{0}' order by Decision", textBox1.Text); is the line with error.
2nd picture edited* I wanted to retrieve a specific value on the database using checkedboxlist
this is the image:
error msg
i wanted to retrieve the data on the database and show the specific value
So a couple of things:
Consider enclosing your DB access code in a using block, and instantiating a new connection using your connection string. This ensures that - either by error or by completion of the block - the connection is correctly closed and disposed off.
Secondly, moving the try/catch inside of the using statement is good practice if you're also working with transactions, as you can commit on completion or rollback in your catch block.
Finally, never use string concatenation to build your queries, when the source of the data you're concatenating with comes from a user control (hell, just never do it). SQL injection is still the OWASP number 3 security risk in software to this day, and it needs to be squashed.
Mandatory reading:
OWASP - Top 10 Web Application Security Risks
SQL Injection - Wikipedia
SQL Injection - Technet
private void button2_Click(object sender, EventArgs e)
{
if (textBox1.Text != "")
{
// a SqlConnection enclosed in a `using` statement will auto-close, and will ensure other resources are correctly disposed
using(SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["DeathWish"].ToString()))
{
try
{
con.Open()
string[] s = new string[] { };
string query = "Select [ID],Decision from Data where [ID]=#id order by Decision";
SqlCommand cmd = new SqlCommand(query, con);
SqlParameter idParam = new SqlParameter();
idParam.ParameterName = "#id";
idParam.Value = textBox1.Text;
cmd.Parameters.Add(idParam);
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
s = dr["Decision"].ToString().Split(',');
}
int length = s.Length;
for (int i = 0; i < length - 1; i++)
{
string fetr = s[i];
for (int j = 0; j <= checkedListBox1.Items.Count - 1; j++)
{
if (checkedListBox1.Items[j].ToString() == s[i])
{
checkedListBox1.SetItemChecked(j, true);
break;
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + ex.ToString());
}
}
}
}
Your Connection is (still) open, so you have to check if it is closed. If it is you can open a new connection.
So try this:
private void button2_Click(object sender, EventArgs e)
{
if (textBox1.Text != "")
{
try
{
if(con.State == ConnectionState.Closed)
{
con.Open();
}
con.ConnectionString = ConfigurationManager.ConnectionStrings["DeathWish"].ToString();
string query = string.Format("Select [ID],Decision from Data where [ID]='{0}' order by Decision", textBox1.Text);
SqlCommand cmd = new SqlCommand(query,con);
SqlDataReader dr = cmd.ExecuteReader();
string[] s = new string[] { };
while (dr.Read())
{
s = dr["Decision"].ToString().Split(',');
}
int length = s.Length;
for (int i = 0; i < length - 1; i++)
{
string fetr = s[i];
for (int j = 0; j <= checkedListBox1.Items.Count - 1; j++)
{
if (checkedListBox1.Items[j].ToString() == s[i])
{
checkedListBox1.SetItemChecked(j, true);
break;
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + ex.ToString());
}
}

Firebird dataReader

I would like to see all of the data with column names in my logfile.
private static void ExecuteSQL()
{
string conn = "User ID=SYSDBA;Password=masterkey;Database=XX.18.137.XXX:C:/ER.TDB;DataSource==XX.18.137.XXX;Charset=NONE;";
FbConnection myConnection = new FbConnection(conn);
FbDataReader myReader = null;
string sql = "SELECT * FROM RDB$RELATIONS";
FbCommand myCommand = new FbCommand(sql, myConnection);
try
{
myConnection.Open();
myCommand.CommandTimeout = 0;
myReader = myCommand.ExecuteReader();
while (myReader.Read())
{
// Log.WriteLog(myReader["rdb$relation_name"].ToString());
}
myConnection.Close();
}
catch (Exception e)
{
Log.WriteLog(e.ToString());
}
}
Right now it's only showing me the rdb$relation_name column.
I want to check the different tables for which I don't have the column's name.
All you need to do is iterate over all fields printing their names before iterating the results:
private static void ExecuteSQL()
{
string conn = "User ID=SYSDBA;Password=masterkey;Database=XX.18.137.XXX:C:/ER.TDB;DataSource==XX.18.137.XXX;Charset=NONE;";
FbConnection myConnection = new FbConnection(conn);
FbDataReader myReader = null;
string sql = "SELECT * FROM RDB$RELATIONS";
FbCommand myCommand = new FbCommand(sql, myConnection);
try
{
myConnection.Open();
myCommand.CommandTimeout = 0;
myReader = myCommand.ExecuteReader();
// 1. print all field names
for (int i = 0; i < myReader.FieldCount; i++)
{
Log.WriteLog(myReader.GetName(i));
}
// 2. print each record
while (myReader.Read())
{
// 3. for each record, print every field value
for (int i = 0; i < myReader.FieldCount; i++)
{
Log.WriteLog(myReader[i].ToString());
}
}
myConnection.Close();
}
catch (Exception e)
{
Log.WriteLog(e.ToString());
}
}
I am pretty sure, that this will give ugly output as it prints every output to a new line. You should be able to change this to print the fields and each record in rows.
public static List<string> GetColumnNames(string queryString)
{
string result = string.Empty;
List<string> listOfColumns = new List<string>();
try
{
using (FbConnection conn = new FbConnection(connString))
{
conn.Open();
using (FbCommand cmd = new FbCommand(queryString, conn))
{
// Call Read before accessing data.
FbDataReader reader = cmd.ExecuteReader();
if (reader.FieldCount > 0)
{
for (int i = 0; i < reader.FieldCount; i++)
{
listOfColumns.Add(reader.GetName(i));
}
}
}
}
}
catch (Exception e)
{
BinwatchLogging.Log(e);
}
return listOfColumns;
// return result;
}
where querystring is your query (eg: select * from yourtablename) and connstring is your firebird connectionstring

Check if query result is null in c#

Hi i am trying to create a validation that checks if its an Unsuccessful SQL Query - if no results are returned, it should catch this error and display a message on screen 'No record found for Client ID: [number]'
The query i currently have fetching the information is below.
protected void ClientSearchBtn_Click(object sender, EventArgs e)
{
//string ClientID = ClientIDTxt.Text;
//Database connection. Calls from web.config.
string MyConnectionString = ConfigurationManager.ConnectionStrings
["RCADSCONNECTION"].ConnectionString;
//SQL Connection
SqlConnection myConnection = new SqlConnection();
myConnection.ConnectionString = MyConnectionString;
//myConnection.Open();
//SQL string
try
{
SqlCommand cmd = new SqlCommand("SELECT CN.ClientID, CI.NNN, CN.GivenName1, CN.Surname, CI.DateOfBirth, CI.Gender FROM [RioOds].dbo.ClientIndex CI LEFT JOIN [RioOds].[dbo].[ClientName] CN ON CN.ClientID = CI.ClientID AND CN.AliasType = '1' AND CN.EndDate IS NULL WHERE CN.ClientID = #clientid", myConnection);
cmd.Parameters.Add("#clientid", SqlDbType.Int).Value = ClientIDTxt.Text;
myConnection.Open();
var reader = cmd.ExecuteReader();
StringBuilder sb = new StringBuilder();
while (reader.Read())
{
for (int i = 0; i < reader.FieldCount; i++)
{
if (i != 0)
{
sb.Append(" | ");
}
sb.Append(reader[i].ToString());
}
sb.AppendLine();
ClientIDCell.Text = reader[0].ToString();
NNNCell.Text = reader[1].ToString();
FirstNameCell.Text = reader[2].ToString();
SurnameCell.Text = reader[3].ToString();
DobCell.Text = reader[4].ToString();
GenderCell.Text = reader[5].ToString();
}
//Show the results table
queryResultsTable.Visible = true;
ResultsLabel.Text = sb.ToString();
submitButton.Enabled = true;
resultsButton.Enabled = true;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
myConnection.Close();
}
myConnection.Close();
}
I am unsure how to go by doing this. I do understand itll be an if statement but unsure how to compare an sql query return to being null.
reader.Read() returns true if there are more rows to read. First time only if it is false that means reader has no data.
if(!reader.Read())
//Your message
else
{
do
{
for (int i = 0; i < reader.FieldCount; i++)
{
if (i != 0)
{
sb.Append(" | ");
}
sb.Append(reader[i].ToString());
}
sb.AppendLine();
ClientIDCell.Text = reader[0].ToString();
NNNCell.Text = reader[1].ToString();
FirstNameCell.Text = reader[2].ToString();
SurnameCell.Text = reader[3].ToString();
DobCell.Text = reader[4].ToString();
GenderCell.Text = reader[5].ToString();
} while (reader.Read());
}
Another option is to check the property HasRows on reader. It's true when there is data in it.
if(!reader.HasRows)
//Your error message goes from here
else
//Do your stuff

Categories