AS400 RPG Program not returning anything - c#

I have the following code. The program just exits, no value returned from call. Any ideas?
AS400System system = new AS400System();
system.Define(ConfigurationManager.AppSettings["AS400Server"]);
system.UserID = ConfigurationManager.AppSettings["AS400User"];
system.Password = ConfigurationManager.AppSettings["AS400Password"];
system.IPAddress = "10.98.1.21";
system.Connect(cwbcoServiceEnum.cwbcoServiceRemoteCmd);
if(system.IsConnected(cwbcoServiceEnum.cwbcoServiceRemoteCmd) == 1) {
Program program = new Program();
program.LibraryName = "P2PTST";
program.ProgramName = "AUI0XFR";
program.system = system;
program.system.Signon();
string paramStatus = "A";
Int64 paramStockItem = Int64.Parse(t.EtagNumber);
Guid paramGuid = Guid.NewGuid();
string paramReturn;
StringConverter stringConverter = new StringConverter();
ProgramParameters parameters = new ProgramParameters();
parameters.Append("ApiIGuid", cwbrcParameterTypeEnum.cwbrcInout, 38);
parameters.Append("StockItemNumber", cwbrcParameterTypeEnum.cwbrcInout, 20);
parameters.Append("ItemStatus", cwbrcParameterTypeEnum.cwbrcInout, 1);
parameters.Append("ReturnCode", cwbrcParameterTypeEnum.cwbrcInout, 7);
parameters["ApiIGuid"].Value = stringConverter.ToBytes(paramGuid.ToString().PadRight(38, ' '));
parameters["StockItemNumber"].Value = stringConverter.ToBytes(paramStockItem.ToString().PadRight(20, ' '));
parameters["ItemStatus"].Value = stringConverter.ToBytes(paramStatus.ToString());
try{
program.Call(parameters);
paramReturn = stringConverter.FromBytes(parameters["ReturnCode"].Value);
system.Disconnect(cwbcoServiceEnum.cwbcoServiceAll);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}

We just went through this and had the same issues, so decided to create and use a stored procedure to accomplish this in .NET. Because we were concerned about having the 400 side distribute the code to create a stored procedure, it ended up being very quick to go ahead and create the procedure on the PC side, followed by our remote command, so no additional changes were necessary on the 400 side.
My environment is Win7 x64 running VS2012 C#, CAX V7.1, and importing both IBM.Data.DB2.iSeries, and System.Data;
I need System.Data for the Parameters. That ended up being critical to get data back!
I send the 400 two params, filesetID and a name. I get back a number and a uuid.
(but they are all characters!)
It looks something like this:
public void RemoteCmd(ref PicMeta pm)
{
iDB2Connection cn;
try
{
using (cn = new iDB2Connection("DataSource=<servername/IP>; UserID="<user>"; Password="<pass>";"))
{
cn.Open();
using (iDB2Command cm = cn.CreateCommand())
{
//Place a try/catch here, so it will create the procedure the first time, or any time it has been removed from the 400. If already set, it will fail, and you'll go directly to the remote command.
try
{
//Here we create a procedure and execute or continue.
cm.CommandText = "CREATE PROCEDURE LIBRARY.SP_PICGETID(INOUT FSET CHAR (1 ), INOUT UNIT CHAR (6 ), INOUT NEXTID CHAR (3 ), INOUT UUID CHAR (36 )) LANGUAGE RPGLE NOT DETERMINISTIC NO SQL CALLED ON NULL INPUT EXTERNAL NAME LIBRARY.PICGETID PARAMETER STYLE GENERAL";
cm.ExecuteNonQuery();
}
catch (Exception ex)
{
Console.Out.WriteLine(ex.Message);
}
//Continue - create and call the command
//ParameterDirection needs "using System.Data;"
cm.CommandTimeout = 0;
cm.CommandType = System.Data.CommandType.StoredProcedure;
cm.CommandText = "LIBRARY.SP_PICGETID";
iDB2Parameter p = new iDB2Parameter();
p.ParameterName = "FSET";
p.Direction = ParameterDirection.Input;
p.iDB2DbType = iDB2DbType.iDB2Char;
p.Size = 1;
p.iDB2Value = pm.fileset;
cm.Parameters.Add(p);
p = new iDB2Parameter();
p.ParameterName = "UNIT";
p.Direction = ParameterDirection.Input;
p.iDB2DbType = iDB2DbType.iDB2Char;
p.Size = 6;
p.iDB2Value = pm.unit;
cm.Parameters.Add(p);
p = new iDB2Parameter();
p.ParameterName = "NEXTID";
p.Direction = ParameterDirection.InputOutput;
p.iDB2DbType = iDB2DbType.iDB2Char;
p.Size = 3;
p.iDB2Value = "";
cm.Parameters.Add(p);
p = new iDB2Parameter();
p.ParameterName = "GUUID";
p.Direction = ParameterDirection.InputOutput;
p.iDB2DbType = iDB2DbType.iDB2Char;
p.Size = 36;
p.iDB2Value = "";
cm.Parameters.Add(p);
cm.ExecuteNonQuery();
iDB2ParameterCollection pc = cm.Parameters;
//We get our Out parameters here
pm.nextid = pc["NEXTID"].Value.ToString();
pm.uuid = pc["GUUID"].Value.ToString();
}
cn.Close();
}
}
catch (Exception e)
{
Console.Out.WriteLine(e.Message);
}
return;
}
Hope this helps!

Related

How to Send Database Table Contents to API?

I have records in a SQL Server database table that need to be transmitted to a payment processing API. Only table records where Transmitted = 0 are to be sent to the API. I found this question which helps me to understand the error at hand.
I want to read the records from my database table into a C# class, parse into JSON, and send via API call. I've tried using Entity Framework Core but receive Null Reference exception when I called the stored procedure and add the results to my model class as follows:
public async Task<IEnumerator<Onboarding>> GetOnboardingList()
{
try
{
using (var context = new SOBOContext())
{
var ob = await context.Onboarding
//.Where(o => o.Transmitted == false)
.FromSql("Execute GetUnsentOnboardingRecords_sp")
.ToListAsync();
Console.WriteLine(ob.ToArray());
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return new OnboardingList().GetEnumerator();
}
When attempting to use Entity Framework Core, I created the OnboardingList class as below:
public class OnboardingList : IEnumerable<Onboarding>
{
private readonly List<Onboarding> _onboarding;
public IEnumerator<Onboarding> GetEnumerator()
{
return _onboarding?.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _onboarding.GetEnumerator();
}
}
I then reverted to SqlDataReader that calls the stored procedure. The method, in part, is as follows:
var listOnboardingModel = new List<Onboarding>();
try
{
using (SqlConnection connection = new SqlConnection(builder.ConnectionString))
{
SqlCommand cmd = new SqlCommand("GetUnsentOnboardingRecords_sp", connection)
{
CommandType = CommandType.StoredProcedure
};
connection.Open();
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
listOnboardingModel.Add(new Onboarding
{
OnboardingId = reader[1] as int? ?? 0,
UserId = reader[2] as int?,
UserName = reader[3].ToString(),
FirstName = reader[4].ToString(),
MiddleInitial = reader[5].ToString(),
Lastname = reader[6].ToString(),
DateOfBirth = reader[7].ToString(),
Ssn = reader[8].ToString(),
Email = reader[9].ToString(),
Address1Line1 = reader[10].ToString(),
Address1Line2 = reader[11].ToString(),
Address1ApartmentNumber = reader[12].ToString(),
Address1City = reader[13].ToString(),
Address1State = reader[14].ToString(),
Address1ZipCode = reader[15].ToString(),
Address1Country = reader[16].ToString(),
DayPhone = reader[17].ToString(),
EveningPhone = reader[18].ToString(),
PhonePin = reader[19].ToString(),
MerchantSourceIp = reader[20].ToString(),
ThreatMetrixPolicy = reader[21].ToString(),
SessionId = reader[22].ToString(),
BankAccount1CountryCode = reader[23].ToString(),
BankAccount1Name = reader[24].ToString(),
BankAccount1Description = reader[25].ToString(),
BankAccount1Number = reader[26].ToString(),
BankAccount1OwnershipType = reader[27].ToString(),
BankAccount1Type = reader[28].ToString(),
BankAccount1BankName = reader[29].ToString(),
BankAccount1RoutingNumber = reader[30].ToString(),
BankAccount2CountryCode = reader[31].ToString(),
BankAccount2Name = reader[32].ToString(),
BankAccount2Number = reader[33].ToString(),
BankAccount2OwnershipType = reader[34].ToString(),
BankAccount2Type = reader[35].ToString(),
BankAccount2BankName = reader[36].ToString(),
BankAccount2Description = reader[37].ToString(),
BankAccount2RoutingNumber = reader[38].ToString(),
AuthSginerFirstName = reader[39].ToString(),
AuthSignerLastName = reader[40].ToString(),
AuthSignerTitle = reader[41].ToString(),
AverageTicket = reader[42] as int? ?? 0,
BusinessLegalName = reader[43].ToString(),
BusinessApartmentNumber = reader[44].ToString(),
BusinessAddressLine1 = reader[45].ToString(),
BusinessAddressLine2 = reader[46].ToString(),
BusinessCity = reader[47].ToString(),
BusinessState = reader[48].ToString(),
BusinessZipCode = reader[49].ToString(),
BusinessCountry = reader[50].ToString(),
BusinessDescription = reader[51].ToString(),
DoingBusinessAs = reader[52].ToString(),
Ein = reader[53].ToString(),
HighestTicket = reader[54] as int? ?? 0,
MerchantCategoryCode = reader[55].ToString(),
MonthlyBankCardVolume = reader[56] as int? ?? 0,
OwnerFirstName = reader[57].ToString(),
OwnerLastName = reader[58].ToString(),
OwnerSsn = reader[59].ToString(),
OwnerDob = reader[60].ToString(),
OwnerApartmentNumber = reader[61].ToString(),
OwnerAddress = reader[62].ToString(),
OwnerAddress2 = reader[63].ToString(),
OwnerCity = reader[64].ToString(),
OwnerRegion = reader[65].ToString(),
OwnerZipCode = reader[66].ToString(),
OwnerCountry = reader[67].ToString(),
OwnerTitle = reader[68].ToString(),
OwnerPercentage = reader[69].ToString(),
BusinessUrl = reader[70].ToString(),
CreditCardNumber = reader[71].ToString(),
ExpirationDate = reader[72].ToString(),
NameOnCard = reader[73].ToString(),
PaymentMethodId = reader[74].ToString(),
PaymentBankAccountNumber = reader[75].ToString(),
PaymentBankRoutingNumber = reader[76].ToString(),
PaymentBankAccountType = reader[77].ToString(),
Transmitted = reader[78] as bool?,
TransmitDate = reader[79].ToString(),
InternationalId = reader[80].ToString(),
DriversLicenseVersion = reader[81].ToString(),
DocumentType = reader[82].ToString(),
DocumentExpDate = reader[83].ToString(),
DocumentIssuingState = reader[84].ToString(),
MedicareReferenceNumber = reader[85].ToString(),
MedicareCardColor = reader[86].ToString(),
PaymentBankAccountName = reader[87].ToString(),
PaymentBankAccountDescription = reader[88].ToString(),
PaymentBankCountryCode = reader[89].ToString(),
PaymentBankName = reader[90].ToString(),
PaymentBankOwnershipType = reader[91].ToString()
});
}
}
connection.Close();
}
Console.WriteLine(listOnboardingModel);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return listOnboardingModel;
When I run the console application, I receive the Error Exception thrown: 'System.IndexOutOfRangeException' in System.Data.SqlClient.dll
Index was outside the bounds of the array.
How do I prevent the above out of range exception and also ensure that all qualifying records from my database table are included for transmission?
You appear to have two distinct issues:
You .ToString() a null value, which causes null reference exception.
An ordinal is likely out of bounds, a column does not match the numeric value provided causing it to be out of bounds.
Check for DBNull.Value otherwise bullet point one will occur.
My assumption would be that you start with one, while index's are zero based. So the first column would start at zero not one.
You should lookup Dapper or some built in utilities for SqlDataReader to leverage cleaner code calls to build your object. Dapper would condense the code by simply doing:
IEnumerable<Sample> GetSamples() => dbConnection.Query<Sample>(...);
As long as the column name matches the property name, it'll populate. Based on the entity provided it looks pretty simple, but checkout the documentation.
Also you should wrap command in using statement like, that way you do not have someone accidentally call a command.Dispose() in the middle of your connection block on accident:
using(var connection = new SqlConnection(...))
using(var command = new SqlCommand(..., ...))
{
connection.Open();
...
using(var reader = command.ExecuteReader())
while(reader.Read())
{
}
}

C# Bizarre Object Reference Not Set error with custom class [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 3 years ago.
I have a strange issue where a piece of code that I run all the time is suddenly throwing a "System.NullReferenceException: Object reference not set to an instance of an object." error.
The error occurs on a line involving a custom class that I made to simplify running TSQL action queries with parameters. With the class, I just have to use the naming convention #Param0, #Param1, etc, and pass an array of this type:
public struct SQLParam
{
private SqlDbType m_Type;
private dynamic m_Value;
public SqlDbType Type
{
get { return m_Type; }
set { m_Type = value; }
}
public dynamic Value
{
get { return m_Value; }
set { m_Value = value; }
}
public SQLParam (SqlDbType ValType, dynamic val)
{
m_Value = val;
m_Type = ValType;
}
public SQLParam(SqlParameter sqlParameter)
{
m_Value = sqlParameter.Value;
m_Type = sqlParameter.SqlDbType;
}
}
...into a method of an object of the class GCDB, called "ActionQueryWithParams", and it works. Except this one time.
Here's the code that's having trouble. I'm including various examples of code that DOES work, and marking the code that DOESN'T in comments:
GCDB GeekConn = new GCDB();
string sID = "";
string sRecurrenceID = JobRecurrenceID.Text.ToString();
if (string.IsNullOrEmpty(JobID.Text.ToString())) //added record
{
//insert job --- THIS WORKS
SQLParam[] paramslist = new SQLParam[6];
string sSQL = "INSERT INTO [dbo].[Jobs] ([CustomerID], [JobName], [JobDescription], [IsRecurringJob], [JobStatusID], [LastModifiedByStaffID]) " +
"OUTPUT INSERTED.JobID " +
"VALUES(#Param0, #Param1, #Param2, #Param3, #Param4, #Param5)";
paramslist[0] = new SQLParam(SqlDbType.Int, Convert.ToInt32(cboCustomerID.SelectedValue));
paramslist[1] = new SQLParam(SqlDbType.VarChar, JobName.Text);
paramslist[2] = new SQLParam(SqlDbType.VarChar, JobDescription.Text);
paramslist[3] = new SQLParam(SqlDbType.Bit, Convert.ToBoolean(IsRecurringJob.Checked));
paramslist[4] = new SQLParam(SqlDbType.Int, Convert.ToInt32(cboJobStatusID.SelectedValue));
paramslist[5] = new SQLParam(SqlDbType.Int, System.Web.HttpContext.Current.Session["StaffID"]);
GeekConn.ActionQueryWithParams(sSQL, paramslist);
if (GeekConn.InsertedID != null)
{
sID = GeekConn.InsertedID.ToString();
}
paramslist = null;
//insert new assignment (if applicable - if adding a job to a staff person's list) -- THIS WORKS
if (!string.IsNullOrEmpty(AssignedToStaffID.Text.ToString()))
{
paramslist = new SQLParam[2];
sSQL = "INSERT INTO [dbo].[JobAssignments] ([JobID], [StaffID]) " +
"SELECT #Param0 AS JobID, #Param1 AS StaffID " +
"WHERE NOT EXISTS(SELECT * FROM[dbo].[JobAssignments] WHERE JobID = #Param0 AND StaffID = #Param1)";
paramslist[0] = new SQLParam(SqlDbType.Int, Convert.ToInt32(sID));
paramslist[1] = new SQLParam(SqlDbType.Int, Convert.ToInt32(AssignedToStaffID.Text.ToString()));
GeekConn.ActionQueryWithParams(sSQL, paramslist);
}
paramslist = null;
}
else //edited record
{
//do the main update -- THIS WORKS
SQLParam[] paramslist = new SQLParam[7];
string sSQL = "UPDATE[dbo].[Jobs] " +
"SET [CustomerID] = #Param0 " +
",[JobName] = #Param1 " +
",[JobDescription] = #Param2 " +
",[IsRecurringJob] = #Param3 " +
",[JobStatusID] = #Param4 " +
",[LastModifiedByStaffID] = #Param5 " +
",[DateModified] = getdate() " +
"WHERE [JobID] = #Param6";
paramslist[0] = new SQLParam(SqlDbType.Int, Convert.ToInt32(cboCustomerID.SelectedValue));
paramslist[1] = new SQLParam(SqlDbType.VarChar, JobName.Text);
paramslist[2] = new SQLParam(SqlDbType.VarChar, JobDescription.Text);
paramslist[3] = new SQLParam(SqlDbType.Bit, Convert.ToBoolean(IsRecurringJob.Checked));
paramslist[4] = new SQLParam(SqlDbType.Int, Convert.ToInt32(cboJobStatusID.SelectedValue));
paramslist[5] = new SQLParam(SqlDbType.Int, System.Web.HttpContext.Current.Session["StaffID"]);
paramslist[6] = new SQLParam(SqlDbType.Int, Convert.ToInt32(JobID.Text));
GeekConn.ActionQueryWithParams(sSQL, paramslist);
paramslist = null;
//auto insert new occurrence (if this is a recurring job and there are no occurrences already) -- THIS THROWS AN ERROR
if ((IsRecurringJob.Checked) && (JobRecurrenceID.Text.ToString() == ""))
{
paramslist = new SQLParam[2];
sSQL = "INSERT INTO [dbo].[JobRecurrences] ([JobID], [StatusLastModified], [LastModifiedByStaffID]) " +
"OUTPUT INSERTED.[JobRecurrenceID] " +
"SELECT #Param0 AS JobID, getdate(), #Param1 AS StaffID " +
"WHERE NOT EXISTS (SELECT * FROM [dbo].[JobRecurrences] WHERE JobID = #Param0)";
paramslist[0] = new SQLParam(SqlDbType.Int, Convert.ToInt32(JobID.Text));
paramslist[1] = new SQLParam(SqlDbType.Int, System.Web.HttpContext.Current.Session["StaffID"]);
// ERROR IS HERE: System.NullReferenceException: Object reference not set to an instance of an object.
GeekConn.ActionQueryWithParams(sSQL, paramslist);
if (GeekConn.InsertedID != null)
{
sRecurrenceID = GeekConn.InsertedID.ToString();
}
}
paramslist = null;
}
GeekConn = null;
I've confirmed that the SQL statement for auto-inserting a new occurrence works in SSMS. And, as far as I can tell, there's nothing in the broken code that isn't also in the working code. Can anybody spot anything I'm missing?
Many thanks!
Many thanks, all! The problem appears to have fixed itself when I fixed another issue (where it wasn't always loading the most recent JobRecurrence into JobRecurrenceID.Text on load).
I ran another test (using the debugger, as recommended), and it does appear to work correctly when the query is actually inserting a record. The issue was that I sometimes had the query run but, because of the WHERE condition (NOT EXISTS), it wasn't actually inserting a record, and it seems it was probably breaking this line of code in the GCDB.ActionQueryWithParams method (only including relevant code):
bool bolIsInsert = (sSQLUpper.Contains("OUTPUT INSERTED."));
try
{
if (bolIsInsert)
{
cmd.Parameters.Add("#ID", SqlDbType.Int, 4).Direction = ParameterDirection.Output;
InsertedID = (int)cmd.ExecuteScalar();
} else
{
cmd.ExecuteNonQuery();
}
}
catch (SqlException e)
{
Error = e.Message.ToString();
}
Apparently I need to include a way to handle INSERT statements that did not actually insert anything. Hmm... Well, that's a separate question. :)

Parameter '?user_email' not found in the collection

I am using MySql 5.6x with Visual Studio 2015, windows 10, 64-bit. C# as programming language. In my CRUD.cs (Class file) i have created the following method:
public bool dbQuery(string sql,string[] paramList= null)
{
bool flag = false;
try
{
connect();
cmd = new MySqlCommand(sql,con);
cmd.Prepare();
if(paramList != null){
foreach(string i in paramList){
string[] valus = i.Split(',');
string p = valus[0];
string v = valus[1];
cmd.Parameters[p].Value = v;
}
}
if (cmd.ExecuteNonQuery() > 0)
{
flag = true;
}
}
catch (Exception exc)
{
error(exc);
}
}
I am passing the query and Parameters List like this:
protected void loginBtn_Click(object sender, EventArgs e)
{
string sql = "SELECT * FROM dept_login WHERE (user_email = ?user_email OR user_cell = ?user_cell) AND userkey = ?userkey";
string[] param = new string[] {
"?user_email,"+ userid.Text.ToString(),
"?user_cell,"+ userid.Text.ToString(),
"?userkey,"+ userkey.Text.ToString()
};
if (db.dbQuery(sql, param))
{
msg.Text = "Ok";
}
else
{
msg.Text = "<strong class='text-danger'>Authentication Failed</strong>";
}
}
Now the problem is that after the loop iteration complete, it directly jumps to the catch() Block and generate an Exception that:
Parameter '?user_email' not found in the collection.
Am i doing this correct to send params like that? is there any other way to do the same?
Thanks
EDIT: I think the best way might be the two-dimensional array to collect the parameters and their values and loop then within the method to fetch the parameters in cmd.AddWidthValues()? I may be wrong...
In your dbQuery you don't create the parameters collection with the expected names, so you get the error when you try to set a value for a parameter that doesn't exist
public bool dbQuery(string sql,string[] paramList= null)
{
bool flag = false;
try
{
connect();
cmd = new MySqlCommand(sql,con);
cmd.Prepare();
if(paramList != null){
foreach(string i in paramList){
string[] valus = i.Split(',');
string p = valus[0];
string v = valus[1];
cmd.Parameters.AddWithValue(p, v);
}
}
if (cmd.ExecuteNonQuery() > 0)
flag = true;
}
catch (Exception exc)
{
error(exc);
}
}
Of course this will add every parameter with a datatype equals to a string and thus is very prone to errors if your datatable columns are not of string type
A better approach would be this one
List<MySqlParameter> parameters = new List<MySqlParameter>()
{
{new MySqlParameter()
{
ParameterName = "?user_mail",
MySqlDbType= MySqlDbType.VarChar,
Value = userid.Text
},
{new MySqlParameter()
{
ParameterName = "?user_cell",
MySqlDbType= MySqlDbType.VarChar,
Value = userid.Text
},
{new MySqlParameter()
{
ParameterName = "?userkey",
MySqlDbType = MySqlDbType.VarChar,
Value = userkey.Text
},
}
if (db.dbQuery(sql, parameters))
....
and in dbQuery receive the list adding it to the parameters collection
public bool dbQuery(string sql, List<MySqlParameter> paramList= null)
{
bool flag = false;
try
{
connect();
cmd = new MySqlCommand(sql,con);
cmd.Prepare();
if(paramList != null)
cmd.Parameters.AddRange(paramList.ToArray());
if (cmd.ExecuteNonQuery() > 0)
{
flag = true;
}
}
catch (Exception exc)
{
error(exc);
}
}
By the way, unrelated to your actual problem, but your code doesn't seem to close and dispose the connection. This will lead to very nasty problems to diagnose and fix. Try to use the using statement and avoid a global connection variable
EDIT
As you have noticed the ExecuteNonQuery doesn't work with a SELECT statement, you need to use ExecuteReader and check if you get some return value
using(MySqlDataReader reader = cmd.ExecuteReader())
{
flag = reader.HasRows;
}
This, of course, means that you will get troubles when you want to insert, update or delete record where instead you need the ExecuteNonQuery. Creating a general purpose function to handle different kind of query is very difficult and doesn't worth the work and debug required. Better use some kind of well know ORM software like EntityFramework or Dapper.
Your SQL Commands' Parameters collection does not contain those parameters, so you cannot index them in this manner:
cmd.Parameters[p].Value = v;
You need to add them to the Commands' Parameters collection in this manner: cmd.Parameters.AddWithValue(p, v);.

Listbox Selected Value Issue

I have a list box on my WinForms application which populates with the following SQL code in C#:
private void PopulateClients()
{
string sqlText = "SELECT ClientID, ClientName FROM tblClients;";
cSqlQuery cS = new cSqlQuery(sqlText, "table");
lbxClient.DataSource = cS.cTableResults;
lbxClient.DisplayMember = "ClientName";
lbxClient.ValueMember = "ClientID";
}
So whilst the list box displays client names, the value it should return when selected is the numerical clientID.
However, later in the code -
private void btnAddNewJob_Click(object sender, EventArgs e)
{
try
{
string strNewJobName = txtNewJobName.Text;
string strNewJobRef = txtNewJobRef.Text;
int intNewJobClient = (int)lbxClient.SelectedValue;
string sqlText = "INSERT INTO tblJobs (JobID, JobClient, JobRef, JobName) " +
"VALUES (#JobID, #JobClient, #JobRef, #JobName);";
SqlCommand sqlCom = new SqlCommand(sqlText);
sqlCom.Parameters.Add("#JobID", SqlDbType.Int);
sqlCom.Parameters.Add("#JobClient", SqlDbType.Int);
sqlCom.Parameters.Add("#JobRef", SqlDbType.Text);
sqlCom.Parameters.Add("#JobName", SqlDbType.Text);
cConnectionString cS = new cConnectionString();
sqlCom.Parameters["#JobID"].Value = cS.NextID("JobID", "tblJobs");
sqlCom.Parameters["#JobClient"].Value = intNewJobClient;
sqlCom.Parameters["#JobRef"].Value = strNewJobRef;
sqlCom.Parameters["#JobName"].Value = strNewJobName;
cSqlQuery cQ = new cSqlQuery(sqlCom, "non query");
PopulateJobs();
txtNewJobName.Text = "";
txtNewJobRef.Text = "";
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Fails on the third line
int intNewJobClient = (int)lbxClient.SelectedValue;
With an invalid cast. As far as I can see the listbox is still returning the Client Name, whereas it should be returning then numerical clientID (int).
Any ideas?
Your code should work - just tested that.
Make sure that the data you are binding to is correct - especially ClientID
also make sure that the value is selected before casting to int
Hope it helps
lbxClient.SelectedValue is a string. It should be converted to an int like so:
int intNewJobClient = Convert.ToInt32(lbxClient.SelectedValue);
Hope this helps.
In the end I had to do this:
int intClient = 0;
try
{
intClient = (int)lbxClient.SelectedValue;
}
catch (Exception)
{
intClient = 0;
}
Which I feel like is a bit of a fudge - but it works!
You code should work, However you should place a sanity check on the SelectedValue on the index.
if (lbxClient.SelectedIndex != -1)
{
int intClient = 0;
try
{
intClient = Convert.ToInt32(lbxClient.SelectedValue);
}
catch (Exception)
{
// catch if the value isn't integer.
intClient = -1;
}
}
I had the same problem but its resolved now by doing this
Replace this
lbxClient.DataSource = cS.cTableResults;
lbxClient.DisplayMember = "ClientName";
lbxClient.ValueMember = "ClientID";
With
lbxClient.DisplayMember = "ClientName";
lbxClient.ValueMember = "ClientID";
lbxClient.DataSource = cS.cTableResults;
Just place the first line "DataSource=" in last and the you will get rid out of it :)
The reason is doing this explained in #Sebastian answer.

C# adding data to SQL database

Background:
I am trying to add data to a SQL DB with C#. I am currently doing so in my script in another class so im using the same code (the code works). However, my current class is using a bunch of recycled code and i am having issues narrowing down why i can not write to the DB. Below is the code i am using and it is broken down to the bare bones minimum code.
What I'm asking for:
anyone to point out some dumb mistake i made or ideas where to troubleshoot. Currently i am just staring at this code and cant see whats wrong.
Thanks in advance!
public void AddAttachmentToDB(XmlNode root, XmlNamespaceManager xmlns, string MessageID, string MailBoxAliasName)
{
//open DB
#region Open DB
if (DbConnection.State != System.Data.ConnectionState.Open)
{
try
{
this.DbConnection.ConnectionString = DbConnectionString;
this.DbConnection.Open();
MailboxListener._logging.LogWrite("[{0}] opened DB Connection in AddAttachmentToDB!",
LoggingLevels.Error,
System.Reflection.MethodBase.GetCurrentMethod().ToString(),
this.DbConnectionString);
}
catch (Exception ex)
{
MailboxListener._logging.LogWrite("[{0}] Failed to open DB Connection! For Machine: {1}",
LoggingLevels.Error,
System.Reflection.MethodBase.GetCurrentMethod().ToString(),
this.DbConnectionString);
MailboxListener._logging.LogWrite("[{0}] Error Returned: {1}",
LoggingLevels.Error,
System.Reflection.MethodBase.GetCurrentMethod().ToString(),
ex.Message.ToString());
}
}
else
{
MailboxListener._logging.LogWrite("[{0}] Failed to open DB Connection in AddAttachmentToDB!",
LoggingLevels.Error,
System.Reflection.MethodBase.GetCurrentMethod().ToString(),
this.DbConnectionString);
}
#endregion
//once db is open try this
try
{
//create test variables
string strMailBoxAliasName = MailBoxAliasName;
string AttachmentFilename = string.Empty;
string strfiletype = string.Empty;
string AttachmentStream = string.Empty;
string strAttachmentID = string.Empty;
string strMessageID = string.Empty;
strMessageID = MessageID;
//fill test variables
AttachmentFilename = "yumyum";
AttachmentStream = "Cheetos";
strMessageID = "123";
strMailBoxAliasName = "user";
strfiletype = ".txt";
strAttachmentID = "12345";
//create sql insert string
String insString = #"INSERT INTO MailboxListenerAttachments Values (#attachmentfilename, #attachmentbody,
#messageID, #mailboxname, #filetype, #attachmentID, #DateAddedToDB)";
//create sql command string
SqlCommand myCommand = new SqlCommand(insString, this.DbConnection);
//add fill test variables to sql insert string
myCommand.Parameters.Add("#attachmentfilename", SqlDbType.VarChar, 100);
myCommand.Parameters["#attachmentfilename"].Value = AttachmentFilename;
myCommand.Parameters.Add("#attachmentbody", SqlDbType.VarChar, 8000);
myCommand.Parameters["#attachmentbody"].Value = AttachmentStream.Trim();
myCommand.Parameters.Add("#messageID", SqlDbType.VarChar, 500);
myCommand.Parameters["#messageID"].Value = strMessageID;
myCommand.Parameters.Add("#mailboxname", SqlDbType.VarChar, 100);
myCommand.Parameters["#mailboxname"].Value = strMailBoxAliasName;
myCommand.Parameters.Add("#filetype", SqlDbType.VarChar, 50);
myCommand.Parameters["#filetype"].Value = strfiletype;
myCommand.Parameters.Add("#attachmentID", SqlDbType.VarChar, 50);
myCommand.Parameters["#attachmentID"].Value = strAttachmentID;
myCommand.Parameters.Add("#DateAddedToDB", SqlDbType.DateTime);
myCommand.Parameters["#DateAddedToDB"].Value = DateTime.UtcNow.ToString();
//run sql command
myCommand.ExecuteNonQuery();
//log sql command events
MailboxListener._logging.LogWrite(
"[{0}] Added attachment {1} to database for messageID: {2}",
LoggingLevels.Informational,
System.Reflection.MethodBase.GetCurrentMethod().ToString(),
AttachmentFilename,
strMessageID
);
//if DB is open, close it
if (DbConnection.State == System.Data.ConnectionState.Open)
{
this.DbConnection.Close();
}
}
//catch errors
catch (Exception ex)
{
MailboxListener._logging.LogWrite("[{0}] Error Returned: {1}",
LoggingLevels.Error,
System.Reflection.MethodBase.GetCurrentMethod().ToString(),
ex.Message.ToString());
}
}
No idea why this doesn't work but this code screams for refactoring:
public void AddAttachmentToDB(
XmlNode root,
XmlNamespaceManager xmlns,
string MessageID,
string MailBoxAliasName
)
{
var strMailBoxAliasName = MailBoxAliasName;
var AttachmentFilename = "yumyum";
var AttachmentStream = "Cheetos";
var strMessageID = "123";
var strMailBoxAliasName = "user";
var strfiletype = ".txt";
var strAttachmentID = "12345";
// Use DateTime when working with dates
var dates123 = new DateTime(2011, 2, 3);
try
{
using (var conn = new SqlConnection(DbConnectionString))
using (var cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = #"INSERT INTO MailboxListenerAttachments Values (#attachmentfilename, #attachmentbody, #messageID, #mailboxname, #filetype, #attachmentID, #DateAddedToDB";
cmd.Parameters.AddWithValue("#attachmentfilename", AttachmentFilename);
cmd.Parameters.AddWithValue("#attachmentbody", AttachmentStream.Trim());
cmd.Parameters.AddWithValue("#messageID", strMessageID);
cmd.Parameters.AddWithValue("#mailboxname", strMailBoxAliasName);
cmd.Parameters.AddWithValue("#filetype", strfiletype);
cmd.Parameters.AddWithValue("#attachmentID", strAttachmentID);
cmd.Parameters.AddWithValue("#DateAddedToDB", dates123);
cmd.ExecuteNonQuery();
}
}
catch (Exception ex)
{
// TODO: Log the exception and propagate it
throw ex;
}
}
Shouldn't Dates123 be of a DateTime type instead of a string?
I think you need to specify input/output directions for all of the paramters.
for example : myCommand.Parameters["#attachmentfilename"].Direction = ParameterDirection.Input
If you really have no idea you can try
Fix your insert statement so it
explicitly names columns maybe your
ordering is incorrect and insert
statement doesnt work
your setting parameters length to
maximum column length values, maybe you
need to set them to actual parameter
values length
I really think that Dates123 is
indeed the most important problem here, it
should be DateTime not string.
So you changed it but you still call DateTime.UtcNow.ToString() , leave it as DateTime type not string.

Categories

Resources