ExecuteNonQuery: Connection property has not been initialized - c#

I'm receiving an error that says that the connection property has not been initialized (see https://imgur.com/CTHIabz). This is confusing, as it is the same code that is in other methods that work just fine. Here is the code:
public bool AddBirthday(string full_name, string month, int day, int year)
{
if (!string.IsNullOrWhiteSpace(full_name) && month.ToString() != "" && day.ToString() != "" && year.ToString() != "")
{
// all required fields were filled out
// determine which month
values = birthdayMonths.Where(v => v.Value == month).ToList();
using (OleDbConnection dbConn = new OleDbConnection(#"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|\qbcdb.mdb"))
{
dbConn.Open();
using (cmd = new OleDbCommand("INSERT INTO birthdays (full_name, birthday_month, birthday_day, birthday_year) VALUES (#full_name, #birthday_month, #birthday_day, #birthday_year)"))
{
foreach (KeyValuePair<int, string> key in values)
{
if (key.Value != "")
{
try
{
cmd.Parameters.AddWithValue("#full_name", full_name);
cmd.Parameters.AddWithValue("#birthday_month", key.Value);
cmd.Parameters.AddWithValue("#birthday_day", day);
cmd.Parameters.AddWithValue("#birthday_year", year);
if (cmd.ExecuteNonQuery() > 0)
{
return true;
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
else
{
MessageBox.Show("No values were given.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
}
dbConn.Close();
}
}
return false;
}
I've gone over the code and checked to make sure the database was in the right location and everything else I could think of. I'm confused on why this work would on another method that uses the same code (almost) when it comes to the database query and binds it to a dvg.
Any help would be appreciated.
Thanks!
Oh btw, it inserts selected values from a listboxes, as demonstrated here:
insertBirthday.Click += (senders, argss) =>
{
if (btd.AddBirthday(name.Text, birthdays.SelectedItem.ToString(), Convert.ToInt32(dayListBox.SelectedItem.ToString()),
Convert.ToInt32(yearListBox.SelectedItem.ToString())))
{
MessageBox.Show("Birthday Added Successfully", "Success", MessageBoxButtons.OK);
}
};

Use this constructor for OleDbCommand: OleDbCommand Constructor (String, OleDbConnection)

You haven't assigned the connection to your OleDbCommand. There are two ways you could to this:
cmd.Connection = dbConn;
or in the constructor:
using (cmd = new OleDbCommand(sql, dbConn)) { ... }
It's also good practice not to open your connection until you are going to use it, i.e. right before cmd.ExecuteNonQuery(). Since you are using a using block, you also don't need to close the connection, that will be taken care of for you, but it's probably not hurting anything.
I recommend separating your database code from your UI code and validation logic (showing MessageBox and checking values) into a separate "repository" class. All of the data necessary to perform the operation should also be passed in as a parameter to your database code so that you don't have any confusing issues where those values aren't being set somewhere else. Calculate the values to insert before calling the method and then pass those as parameters.

Related

Postgresql query returns NullReferenceException

I'm using Selenium + postgre integration in order to validate correct data on database. After an action on UI then I'm using Npgsql library in order to receive scalar value from cell and then use it for assertion.
Code looks line:
public static string GetCreditAmount(string orderId, string accountNumber)
{
string findCreditQuery = $#"SELECT ""Credit"" FROM accounting.""AccountLines"" al INNER JOIN accounting.""Accounts"" acc ON al.""Account_FK"" = acc.""Id""
WHERE
""OrderId"" = '{orderId}'
AND ""AccountNumber"" = '{accountNumber}'
ORDER BY al.""CreatedDateUtc"" DESC";
using (var connection = new NpgsqlConnection(Configuration.AdminConnectionString))
{
connection.Open();
var transaction = connection.BeginTransaction();
try
{
var account = connection.ExecuteScalar(findCreditQuery).ToString();
return account;
}
catch (NullReferenceException e)
{
Thread.Sleep(3000);
var account = connection.ExecuteScalar(findCreditQuery).ToString();
return account;
}
catch (Exception e)
{
transaction.Rollback();
throw e;
}
}
}
The problem which I'm receiving is NullReferenceException, however results are really random. In one test I'm firing & asserting few times where in like 85% it does not work (Null reference) and from time to time in like 15% it works (test passed). Strange case is that assertion which was fine in one run fails in another one.
I was trying to add static sleeps (Thread.Sleep) in order to give database few extra second for proceeding but all it still fails.
Is there any proper solution which can be used?
If you do this:
object o = null;
string s = o.ToString();
I believe you will get the same error. I believe the issue is your database object is null.
This will probably fix it:
object o = connection.ExecuteScalar(findCreditQuery);
string account = o == null ? null : o.ToString();
Alternatively, you can implement a DbDataReader and use the IsDbNull method. It will be more work but might also be more scalable if you plan to do more than what's currently being done:
string account;
using (NpgsqlCommand cmd = new NpgsqlCommand(findCreditQuery, connection))
{
using (NpgsqlDataReader reader = cmd.ExecuteReader())
{
reader.Read();
if (!reader.IsDBNull(0))
account = reader.GetString(0);
}
}

Delete a SQL table record using C# & SQL WHERE clause

I want to delete a SQL table record using C#. I already tried the below mentioned code snippet but it didn't work. However the message is showing 'Data Record Deleted!' as it should it be. I can't find an issue in the statement also.
private void delemp_Click(object sender, EventArgs e)
{
try
{
if(MessageBox.Show("do you really want to delete this","Deleting ", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.Yes)
{
EMP.DELETEMP(this.dataGridView1.CurrentRow.Cells[0].Value.ToString());
MessageBox.Show("deleting Seccussfully","Deleting ");
this.dataGridView1.DataSource = EMP.GET_ALL_EMP();
}
else
{
MessageBox.Show("Deleting Canceled ");
}
}
catch (Exception)
{
MessageBox.Show("ERROR");
}
}
and this is the class
public void DELETEMP(string ID)
{
DAL.dataaccesslayer DAL = new DAL.dataaccesslayer();
DAL.open();
SqlParameter[] param = new SqlParameter[1];
param[0] = new SqlParameter("#ID", SqlDbType.NVarChar);
param[0].Value = ID;
DAL.executcommand("DELETEMP", param);
DAL.close();
}
EMP.DELETEMP() doesn't return a result of any kind so it will be impossible for you to know whether the record was actually deleted or not. As long as EMP.DELETEMP() doesn't throw an exception, which it might not, your code will always display the "deleting Seccussfully" message.
So, most likely EMP.DELETEMP() isn't actually deleting anything. To fix this, you are going to need to figure out why. It looks like there is maybe a stored procedure in the database called DELETEMP that takes an ID (integer?) parameter. Have you tested this stored procedure?
Also, we are assuming that DAL works as intended. I do not recognize this. It is possibly not fully legitimate because the method you are calling is DAL.executcommand() which isn't even spelled correctly.

SystemInvalidOperationException

I am trying to save this to my datebase but I keep getting this error
System.InvalidOperationException
here is my code.
protected void btnSend_Click(object sender, EventArgs e)
{
con.Open();
cmd = new SqlCommand(#"INSERT INTO orders2
(orderName,orderFile,orderType,orderPrice,orderQuantity,orderShipped)
VALUES
('"+DropDownList1.SelectedValue+"','"+lblFile.Text+"','"+lblPrice.Text+"','"+txtQuantity.Text+"','"+DateTime.Now+"')",con);
cmd.ExecuteNonQuery();
con.Close();
lblFinished.Text = "Order has been submitted for process.";
}
WhoAmI is probably right, however your code could be greatly improved to avoid other problems and to also allow you not to allow unhandled exceptions.
I have put extra comments directly in the code:
try
{
// SqlConnection is disposable, so it is recommended to dispose it (using calls Dispose() for you)
using (var con = new SqlConnection(connStr))
{
con.Open();
// this is missing from your code and might the errors actual cause
// SqlCommand is also disposable
using (var cmd = con.CreateCommand())
{
// is is strongly recommended to construct parameterized commands
// to avoid SQL injection (check this - https://technet.microsoft.com/en-us/library/ms161953(v=sql.105).aspx)
cmd.Text = #"
INSERT INTO orders2
(orderName,orderFile,orderType,orderPrice,orderQuantity,orderShipped)
VALUES (#orderName, #orderFile, #orderType, #orderPrice, #orderQuantity, #orderShipped)";
// the parameters - SqlCommand infers parameter type for you
cmd.AddWithValue("#orderName", DropDownList1.SelectedValue);
cmd.AddWithValue("#orderFile", lblFile.Text);
cmd.AddWithValue("#orderType", theMissingParametersForOrderType);
// some conversion might be needed here, as I expect the price to be some number
// with a fixed number of decimals
// e.g. Convert.ToDecimal(lblPrice.Text)
cmd.AddWithValue("#orderPrice", lblPrice.Text);
// same convertion issue as for price
cmd.AddWithValue("#orderQuantity", txtQuantity.Text);
cmd.AddWithValue("#orderShipped", DateTime.Now);
}
}
}
// there are several Exceptions that can be raised and treated separately
// but this at least you can do
catch (Exception exc)
{
// log the error somewhere
// put a breakpoint just below to inspect the full error details
}
// this is executed even if an exception has occurred
finally
{
if (con != null && con.State != ConnectionState.Closed)
con.Close();
}
As a side note, this code belongs to a data layer, no presentation layer. Consider including it within another assembly.
You are inserting 6 values(orderName,orderFile,orderType,orderPrice,orderQuantity,orderShipped) here, but supplied only 5 values. DropDownList1.SelectedValue, lblFile.Text, lblPrice.Text, txtQuantity.Text, DateTime.Now.

SQL Server doesn't recognize my parameter

I've got an ASP.NET MVC site with an admin page where I need to merge two records. I'm passing in two values, #old and #new. After adding those to my SqlCommand object, I call the ExecuteNonQuery(). This is generating an exception with the message saying
stored procedure 'FixDuplicate' expects parameter '#old' which was
not supplied
As you can see below, I'm definitely adding the parameter. All 3 versions that I've tried are there.
What's wrong with this code?
Version 1: (please ignore the syntax of this one, I already removed this code, but I did try it and confirmed that the parameters existed when it reached the ExecuteNonQuery() call)
var sql = "FixDuplicate";
comm.Parameters.Add(new System.Data.SqlClient.SqlParameter("#old", model.Duplicate));
comm.Parameters.Add(new System.Data.SqlClient.SqlParameter("#new", model.Primary));
_dataAccessService.ExecuteSql(conn, comm);
Version 2:
comm.Parameters.AddWithValue("#old", model.Duplicate);
comm.Parameters.AddWithValue("#new", model.Primary);
Version 3:
comm.Parameters.Add("#old", System.Data.SqlDbType.Int);
comm.Parameters[0].Value = model.Duplicate;
comm.Parameters.Add("#new", System.Data.SqlDbType.Int);
comm.Parameters[1].Value = model.Primary;
Lastly, here's the code in the _dataAccessService.ExecuteSql(conn, comm) call:
public void ExecuteSql(SqlConnection connection, SqlCommand command, bool closeConnection = true)
{
if (connection == null)
throw new ArgumentNullException("connection");
if (command == null)
throw new ArgumentNullException("command");
try
{
if (connection.State != ConnectionState.Open)
connection.Open();
try
{
command.ExecuteNonQuery();
}
catch
{
throw;
}
finally
{
if (closeConnection)
command.Dispose();
}
}
catch (Exception ex)
{
throw new Exception("Sorry, an error occurred ExecuteSql: " + ex.Message, ex);
}
finally
{
if (closeConnection)
connection.Dispose();
}
}
Note: I have confirmed that the values for both '#old' and '#new' are set when it gets to the ExecuteNonQuery() line.
Edit: Here's the full code, as it exists:
// Here we need to execute the "FixDuplicate" stored procedure
var sql = "FixDuplicate";
var conn = _dataAccessService.GetConnection("");
var comm = _dataAccessService.GetCommand(conn, sql, System.Data.CommandType.StoredProcedure);
//comm.Parameters.AddWithValue("#old", model.DuplicateWrestler);
//comm.Parameters.AddWithValue("#new", model.PrimaryWrestler);
comm.Parameters.Add("#old", System.Data.SqlDbType.Int);
comm.Parameters[0].Value = model.DuplicateWrestler;
comm.Parameters.Add("#new", System.Data.SqlDbType.Int);
comm.Parameters[1].Value = model.PrimaryWrestler;
_dataAccessService.ExecuteSql(conn, comm);
Probably your model.Duplicate is null. In this case value of parameter will not be set.
If you need to pass null to SqlParameter.Value, use DBNull.Value.
See SqlParameter.Value for reference.
I believe you need to specify a command type:
command.CommandType = CommandType.StoredProcedure;
I suggest you to check with Profiler if old parameter is set or not.
And also try to run this procedure from SQL Server Management Studio to be sure it's working fine.

Parameterized Update

I am trying to update a record in an access file (.accdb). I am trying to use the .net OleDbCommand and OleDbParameters. I am also trying to use a generic model and store all of the commands and parameters in the System.Data.Common abstract equivalents so that I can easily switch over to SQL Server (which I do plan to do)
So here is the actual command being used
EDIT 2/2/2013 - 9:10pm
the command.ExecuteNonQuery is inside the method named ExecuteNonQuery()
the connectionString and command are defined in the DataAccess class constructor
public class DataAccess
{
private string connectionString;
private DbConnection connection;
private DbCommand command;
private DbDataReader reader;
private DataTable data;
public DataAccess()
{
connectionString = ConfigurationSettings.AppSettings["ConnectionString"];
switch (ConfigurationSettings.AppSettings["DataBaseType"])
{
case "oledb":
connection = new OleDbConnection(connectionString);
command = new OleDbCommand(string.Empty, (OleDbConnection)connection);
break;
case "SQL":
connection = new SqlConnection(connectionString);
command = new SqlCommand(string.Empty, (SqlConnection)connection);
break;
default:
break;
}
}
public void ExecuteNonQuery(string SQL, params DbParameter[] parameters)
{
command.CommandType = CommandType.Text;
command.CommandText = SQL;
command.Parameters.AddRange(parameters);
try
{
command.Connection.Open();
try
{
command.ExecuteNonQuery();
}
catch (Exception ex)
{
throw ex;
}
finally
{
command.Connection.Close();
}
}
catch (Exception ex)
{
throw ex;
}
}
public DbParameter NewParameter(string name, object value)
{
DbParameter param;
switch (ConfigurationSettings.AppSettings["DataBaseType"])
{
case "oledb":
param = new OleDbParameter(name, value);
break;
case "SQL":
param = new SqlParameter(name, value);
break;
default:
param = null;
break;
}
return param;
}
These are the properties in the App.Config File
<add key="DataBaseType" value="oledb"/>
<add key="ConnectionString" value="Provider=Microsoft.ACE.OLEDB.12.0;Data Source=data.accdb"/>
Now the problem is when using parameters in an update statement, the update never happens and also never throws an error. Here is the code for it.
EDIT 2/2/2013 - 9:10pm
the function DataAccess.NewParameter is in the first code block
DALayer.ExecuteNonQuery("UPDATE TileTypes SET Title = #Title, Picture = #Picture, Color = #Color WHERE ID = #ID",
DALayer.NewParameter("#Title", titleTextBox.Text.Trim()),
DALayer.NewParameter("#Picture", typePictureBox.ImageLocation),
DALayer.NewParameter("#Color", colorButton.BackColor.ToArgb()),
DALayer.NewParameter("#ID", id));
I have copied the query into access and replaced all of the parameter names with the actual data being passed, this works fine. I have tried replacing all of the parameters in the SQL text to the ? character to no effect. I have tried enclosing all of the table and column names in brackets [] also to no effect.
ID is an AutoNumber field
Title is a Text field
Picture is a Text field
Color is a Long Integer field
This is some example data that was copied directly from the parameters in the watch window for Visual Studio:
"Edit" (title)
-1 (color)
"data\images\Edit_000000.jpg" (picture)
740 (id)
That ID does exist in the database and was unchanged after the query executed.
EDIT 2/2/2013 - 9:10pm
I am not sure how to check which database is actually being updated, the only thing I could think of was that using the same connection string and connection object I did an insert statement with the same ExecuteNonquery method and it worked in the database I was viewing. And the update statement works just fine like this (without parameters):
DALayer.ExecuteNonQuery("UPDATE TileTypes SET Title = '" + titleTextBox.Text +
"', Color = " + colorButton.BackColor.ToArgb() + ", Picture = '" +
imageLocation + "' WHERE ID = " + id);
EDIT 2/2/2013 - 9:41pm
I have used everything.exe to search my computer for all of the data.accdb files on my computer, I have found no actual .accdb files besides the original but I did find these .lnk files, I do not believe they could have altered this process but I will mention it anyway
data.accdb.LNK
What you are trying to do is something I too have done in the past, but allowed to connect to OleDB (such as Access, Visual FoxPro, etc), SQL-Server, SyBase SQLAnywhere and maybe my implementation might help you. First, each of the elements you would use for connecting work on a common interface, such as IDbConnection, IDbCommand, IDbParameter, etc.
The following I'm posting is a small segment of how I originally structured such multi-database connection type. I've stripped a bunch out and not actually tested this stripped version, but it SHOULD be a good baseline for you to run with.
The premise is a baseline "MyConnection" to almost be like an abstract, but has properties and some "common" methods that would exist under EITHER subclassed definition. From this, each of the functions and parameter types are based on the "I"nterface, not a specific. However, each of the derived will create its OWN proper type. This removes the need to "Case" everything. Hope this helps you along with your Data Access Layer development.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
// for OleDB (Access, VFP, etc)
using System.Data.OleDb;
// for SQL-Server
using System.Data.SqlClient;
namespace DataMgmt
{
public class MyConnection
{
// no matter the connection to server, it will require some "handle"
// that is of type "IDbConnection"
protected IDbConnection sqlConnectionHandle;
// when querying, ANY query could have an exception that needs to have
// possible further review for handling
public Exception LastException
{ get; protected set; }
// When calling an execute command (select, insert, update, delete),
// they all can return how many rows affected
public int RowsAffectedByQuery
{ get; protected set; }
// different databases could have different connection strings. Make
// virtual and throw exception so sub-classed must return proper formatted.
public virtual string GetConnectionString()
{ throw new Exception("GetConnectionString() method must be overridden."); }
// each has its own "IDbConnection" type too
protected virtual IDbConnection SQLConnectionHandle()
{ return sqlConnectionHandle; }
public virtual IDbCommand GetSQLDbCommand()
{ throw new Exception("GetSQLDbCommand() method must be overridden."); }
// generic routine to get a data parameter...
public virtual IDbDataParameter AddDbParmSpecificValue(string ParmName, object UnknownValue)
{ throw new Exception("AddDbParmSpecificValue() method must be overwritten per specific connection."); }
// generic "Connection" since they are all based on IDbCommand...
public override bool SQLConnect()
{
// pre-blank exception in case remnant from previous activity
LastException = null;
if (sqlConnectionHandle.State != System.Data.ConnectionState.Open)
try
{
// if not open, always make sure we get updated connection string
// if ever changed by some other "unknown" condition...
sqlConnectionHandle.ConnectionString = GetConnectionString();
sqlConnectionHandle.Open();
}
catch (Exception ex)
{
// Preserve in generic sqlException" property for analysis OUTSIDE this function
LastException = ex;
}
// if NOT connected, display message to user and set error code and exception
if (sqlConnectionHandle.State != System.Data.ConnectionState.Open)
LastException = new Exception("Unable to open database connection.");
// return if it IS successful at opening the connection (or was already open)
return sqlConnectionHandle.State == System.Data.ConnectionState.Open;
}
// likewise disconnect could be common
public void SQLDisconnect()
{
if (sqlConnectionHandle != null)
if (sqlConnectionHandle.State == ConnectionState.Open)
sqlConnectionHandle.Close();
}
public bool SqlExecNonQuery( IDbCommand SQLCmd, DataTable oTbl)
{
// pre-clear exception
LastException = null;
// fill the table...
SQLConnect();
try
{
RowsAffectedByQuery = SQLCmd.ExecuteNonQuery();
}
catch (Exception e)
{
LastException = e;
throw e;
}
finally
{
SQLDisconnect();
}
// Its all ok if no exception error
return LastException == null;
}
}
// Now, build your connection manager per specific type
public class MyAccessConnection : MyConnection
{
public MyAccessConnection()
{ sqlConnectionHandle = new OleDbConnection(); }
public override string GetConnectionString()
{ return "Your Connection String from AppSettings.. any changes if OleDb vs SQL"; }
public override IDbCommand GetSQLDbCommand()
{ return new OleDbCommand( "", (OleDbConnection)sqlConnectionHandle ); }
public override IDbDataParameter AddDbParmSpecificValue(string ParmName, object UnknownValue)
{ return new OleDbParameter( ParmName, UnknownValue ); }
}
public class MySQLConnection : MyConnection
{
public MySQLConnection()
{ sqlConnectionHandle = new SqlConnection(); }
public override string GetConnectionString()
{ return "Your Connection String from AppSettings... any alterations needed??? "; }
public override IDbCommand GetSQLDbCommand()
{ return new SqlCommand ("", (SqlConnection)sqlConnectionHandle); }
public override IDbDataParameter AddDbParmSpecificValue(string ParmName, object UnknownValue)
{ return new SqlParameter(ParmName, UnknownValue); }
}
// Now to implement... pick one... Access or SQL-Server for derivation...
public class MyDataLayer : MyAccessConnection
{
public void SomeSQLCall()
{
IDbCommand sqlcmd = GetSQLDbCommand();
sqlcmd.CommandText = "UPDATE TileTypes SET Title = #Title, "
+ "Picture = #Picture, "
+ "Color = #Color "
+ "WHERE ID = #ID";
sqlcmd.Parameters.Add( AddDbParmSpecificValue( "#Title", titleTextBox.Text.Trim() ));
sqlcmd.Parameters.Add( AddDbParmSpecificValue( "#Picture", typePictureBox.ImageLocation) );
sqlcmd.Parameters.Add( AddDbParmSpecificValue( "#Color", colorButton.BackColor.ToArgb()) );
sqlcmd.Parameters.Add( AddDbParmSpecificValue( "#ID", id));
if( SqlExecNonQuery(sqlcmd))
// Good to go
DoSomethingWithTheData;
else
// Notify of whatever error thrown....
}
}
}
So.. as you can see, my last class specifically is derived from EITHER Access OR SQL. Then, I can create my methods to get data, call updates, whatever. Get a SQL Command (which returns proper type and automatically is attached to its corresponding "Connection Handle" object, prepare the text, add your parameters, execute it.

Categories