SqlDataReader - correct syntax, must I hardcode column number? - c#

I have a database named testDB, which contains table Versions, which contains a column [Release Date] with datetime format.
Now, I want to read it in my C# Windows Service:
protected void SqlConnect()
{
SqlCommand comSql;
DateTime relDate;
SqlDataReader myReader = null;
using (SqlConnection myConnection = new SqlConnection(_server +
_username +
_password +
"Trusted_Connection=yes;" +
"database=testDB; " +
"connection timeout=30"))
{
try
{
myConnection.Open();
comSql = new SqlCommand("select [Release Date] from dbo.Version",
myConnection);
myReader = comSql.ExecuteReader();
while (myReader.Read())
{
//Here's my problem, explained below
}
}
catch
{
}
finally
{
if (myReader != null) myReader.Close();
}
}
}
Now, I want to assign the value stored in that column to relDate variable. However
relDate = myReader.GetDateTime();
requires GetDateTime to have column number passed there (if I understand this right). But I already selected column in my comSql. Is this the correct way to deal with this problem, ie. just putting the column number in the code?
EDIT: Ok judging by the answers I might word this question wrong or something.
I know that I must pass the column index to GetDateTime(). I ask if there's a way to do that without hardcoding it like GetDateTime(0).

You can use GetOrdinal method on the data reader to get ordinal of the column from its string name. In that way, you won't have to hardcode the column index.
GetOrdinal is also useful when you're reading data from the data reader in a loop. You can initialize the index variable before the loop starts and then use it in every iteration of the loop.

Related

I am trying to save inputs using combo boxes and a date time picker to a ms access database and it says : Data type mismatch in criteria Expression

private void button2_Click(object sender, EventArgs e)
{
try
{
using (var con = new OleDbConnection())
{
con.ConnectionString = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\ZwaneZP01\source\repos\HenleyFaultsSystemSbu\Faults.accdb;";
con.Open();
using (var com = new OleDbCommand())
{
com.Connection = con;
com.CommandText = "INSERT INTO Faults ([Date],[Job],[Area],[ReportedBy],[ReportedTo],[Equipment],[Workshop]," +
"[SerialNo],[Delay],[TimeSpent],[FANo],[Category],[Fault],[Action],[Status]) " +
"VALUES (#Date,#Job,#Area,#ReportedBy,#ReportedTo,#Workshop,#Equipment,#Fault,#Action,#Delay,#TimeSpent,#Status,#SerialNo,#FANo,#Category)";
com.Parameters.AddWithValue("#Date", dateTimePicker1.Text);
com.Parameters.AddWithValue("#Job", comboBox1.Text);
com.Parameters.AddWithValue("#Area", AreacomboBox2.Text);
com.Parameters.AddWithValue("#ReportedBy", NameCodeReportedBy.Text);
com.Parameters.AddWithValue("#ReportedTo", ReportedToBox.Text);
com.Parameters.AddWithValue("#Workshop", WorkshopBox.Text);
com.Parameters.AddWithValue("#Equipment", EquipmentBox.Text);
com.Parameters.AddWithValue("#Fault", textBox2.Text);
com.Parameters.AddWithValue("#Action", textBox3.Text);
com.Parameters.AddWithValue("#Delay", DelayBox.Text);
com.Parameters.AddWithValue("#TimeSpent", TimeBox.Text);
com.Parameters.AddWithValue("#Status", checkBox1.Checked);
com.Parameters.AddWithValue("#SerialNo", textBox4.Text);
com.Parameters.AddWithValue("#FANo", textBox5.Text);
com.Parameters.AddWithValue("#Category", CategoryComboBox.Text);
com.ExecuteNonQuery();
}
}
MessageBox.Show("Saved");
}
catch (Exception ex)
{
MessageBox.Show("Not saved: " + ex.Message);
}
}
//So this is not saving to the database
I tried changing the date format as I thought its probably the date but that has not helped either
I expect it to save to the data but I am getting an error about criteria mismatch
The first thing to fix is removing all those AddWithValue and replacing them with
com.Parameters.Add("#Date", OleDbType.DateTime).Value = dateTimePicker1.DateTime;
and so on...
This is important because AddWithValue is not able to pass a parameter of type DateTime as expected by your database table if you give it a string of text. You should alwasy be
precise when providing parameters to your underlying database (MS-Access or not)
But then there is another problem. The OleDb library is not able to recognize the parameters by their names and assign the value to the correct place in your sql.
OleDb pass the parameters values looking at their position in the collection so the parameter #Workshop is assigned to the Equipment field and viceversa the parameter #Equipment is assigned to the Workshop field.
You should arrange your parameter list following the exact order in which the parameter placeholders appears in the sql text and, of course, verify that every parameter placeholder matches the corresponding field to update

Retrieving more than one value from database and store them

What I'm trying to do is retrieve the FullName values where the Username corresponds to the user, which does indeed work, the problem is I don't exactly know how to store the values when there is more than one value, I tried using an array but when there is for example two values, when retrieving it, characterReader[0] will be null and characterReader[1] will have only the first retrieved value, however if there is only 1 value to be retrieve characterReader[0] will no longer be null and display the correct value.
This is my code, I'm not exactly sure this is even the right way:
SqlCommand displayCharactersCMD = new SqlCommand(String.Format("SELECT FullName FROM [Characters] WHERE Username='{0}'", username), con);
displayCharactersCMD.Parameters.AddWithValue("#checkPlayerName", username);
using (SqlDataReader reader = displayCharactersCMD.ExecuteReader())
{
int counter = 0;
while (reader.Read())
{
if (counter != countCharsToVar)
{
characterReader = new string[countCharsToVar];
characterReader[counter] = reader[0].ToString();
counter++;
}
else
break;
}
}
Example when there are two values to be retrieved:
API.consoleOutput("CHAR 1: " + characterReader[0]); - This will become null.
API.consoleOutput("CHAR 2: " + characterReader[1]); - This will contain the first value.
How I intend it to work:
API.consoleOutput("CHAR 1: " + characterReader[0]); - This will display first value.
API.consoleOutput("CHAR 2: " + characterReader[1]); - This will display second value.
Instead of storing values in array, you can utilize List<>. This might help you:
SqlCommand displayCharactersCMD = new SqlCommand("SELECT FullName FROM [Characters] WHERE Username=#checkPlayerName");
displayCharactersCMD.Parameters.AddWithValue("#checkPlayerName", username);
var characterReader = new List<string>();
using (SqlDataReader reader = displayCharactersCMD.ExecuteReader())
{
while (reader.Read())
{
characterReader.Add(reader[0].ToString());
}
}
Here's a really good link from Microsoft: https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/retrieving-data-using-a-datareader
Use the GetString(columnNumber) method to get the whole value from the row. That should make it easy for you.
Hope this helps.
You need to iterate SqlDataReader for each value, calling reader.Read() makes the reader to point to the next row, when it reaches the end and there is no more rows in the resultset it returns false.
When a "read" is done, the reader is moved to point to the next row so you can access all the columns in this way. reader[0] will be the first column, reader[1] for the second column and so on, in your example you only have one column fullname.
You can add all your results to a list in this way:
var values = new List<string>();
using (SqlDataReader reader = displayCharactersCMD.ExecuteReader())
{
while (reader.Read())
{
values.Add(reader[0]);
}
}
Note: as #steve points, parameter does not work that way, you remove the string.format call and use the name of the parameter.
new SqlCommand("SELECT FullName FROM [Characters] WHERE Username=#checkPlayerName"), con);

In visual studio when i trying to add record to ACCESS file :The field is too small to accept the amount of data you attempted to add.

I am trying to add some record to ACCESS file ,as you can see here :
string strconnection = #"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=AccessTemp.mdb";
private void InsertSellItems(List<TTMSModel> lstttms )
{
try
{
foreach (TTMSModel t in lstttms)
{
if (t.TypeMember == "حقیقی") t.TypeMember = "1";
else
{
t.TypeMember = "2";
}
OleDbConnection objconnection = new OleDbConnection(strconnection);
OleDbCommand objcommand = new OleDbCommand("INSERT INTO Foroush_Detail" +
"(KalaKhadamatName,KalaCode,BargashtType,Price,MaliatArzeshAfzoodeh,AvarezArzeshAfzoodeh,HCKharidarTypeCode,KharidarPostCode,KharidarPerCityCode,KharidarTell,KharidarAddress,KharidarName,KharidarLastNameSherkatName,KharidarEconomicNO,KharidarNationalCode,HCKharidarType1Code,CityCode,stateCode,IsSent,Sarjam)" +
"VALUES('فروش'," +"'0'"+",'0','"+t.PriceAmount+"','"+t.MayorAmount+"','"+t.TaxAmount+"','"+t.TypeMember+"','"+t.ZipCode+"','"+t.City+"','"+t.PhoneNumber+"','"+t.Address+"','"+t.Name+"','"+t.Name+"','"+t.EconomicNumber+"','"+t.IntNumber+"','2','"+t.City+"','"+t.Province+"','0','0')",
objconnection);
objconnection.Open();
objcommand.ExecuteNonQuery();
objconnection.Close();
}
}
catch (OleDbException a)
{
MessageBox.Show(a.Message);
}
}
I fetched the data from SQL server 2012.but after executing this query i got this error:
the field is too small to accept the amount of data you attempted to add access 2010.
The table structure is like this :
Best regards
For BargashtType column that is declared as Yes/No type, you are trying to insert فروش .Which is invalid, as the field will accept only 0 or 1 i.e. true or false.
It appears to me you are passing ever value in the query as a string, depite the fact some of the fields are numbers:
'"+t.City+"','"+t.Province+"'
Both of these values have a single quote around them, meaning they are strings, yet the two fields are Numbers.
That means you're leaving Access to do the conversion, you might want to try passing them as numeric values and see if that resolves the problem

C#: Input data from string array into MS Access DB Table

I've searched as much as I can and can't find anything to help me. So what I have is a script that reads/splits and stores data from a .txt file into some arrays. (The one listed here is Vndnbr). What I'm having trouble with is how to go about inputting each entry in the array as an entry under a column in a MS Access table? This is what I have so far:
public void AddToDatabase()
{
OleDbCommand command;
OleDbConnection connection =
new OleDbConnection(#"Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data Source=filepath");
foreach (string x in Vndnbr)
{
cmdstringVND[k] = "insert into Table1 (Vndnbr) Values (x)";
k++;
command = OleDbCommand(cmdstringVND[k],connection);
}
command.Parameters.AddWithValue("?", ReadFromFile("filepath"));
connection.Open();
command.ExecuteNonQuery();
connection.Close();
}
I'm not familiar with the Access library or what should be inserted in the first parameter of AddwithValue as I just copy pasted these lines after doing some research.
If someone could help me with how to add all the data from an array into a table it would be greatly appreciated, thanks.
There are many errors in your code
In your loop you don't use a parameter to store the value to be
inserted
You never creare the command. (Use new)
You try to execute only the last command because the ExecuteNonQuery is outside the loop
public void AddToDatabase()
{
string cmdText = "insert into Table1 (Vndnbr) Values (?)";
using(OleDbConnection connection = new OleDbConnection(.....))
using(OleDbCommand command = new OleDbCommand(cmdText, connection))
{
connection.Open();
command.Parameters.AddWithValue("#p1", "");
foreach (string x in Vndnbr)
{
command.Parameters["#p1"].Value = x;
command.ExecuteNonQuery();
}
}
}
I have changed you code to include the using statement to correctly close and dispose the connection and the command, then I have initialized the command outside the loop, passed a common string with as a parameter placeholder and initialized this parameter with a dummy value.
Inside the loop I have replaced the previous parameter value with the actual value obtained by your Vndnbr list and executed the command.
You'll want to change your SQL to this:
"insert into Table1 (Vndnbr) Values (#x)";
and then the AddWithValue is like this:
command.Parameters.AddWithValue("#x", ReadFromFile("filepath"));
All you're doing is saying, for this parameter name, I want this value assigned.

Adding Data with Same Primary Key Data in ASP.Net

I have a table name AVUKAT and it's columns (AVUKAT, HESAP(Primary KEY), MUSTERI)
All MUSTERI has a one unique HESAP (int).
Simple I have a page like this.
First dropdown is selected MUSTERI, second is AVUKAT
And i automaticly calculating HESAP (int and Primary KEY) with this code. (On the background.)
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
string strConnectionString = ConfigurationManager.ConnectionStrings["SqlServerCstr"].ConnectionString;
SqlConnection myConnection = new SqlConnection(strConnectionString);
myConnection.Open();
string hesapNo = DropDownList1.SelectedItem.Value;
string query = "select A.HESAP_NO from YAZ..MARDATA.S_TEKLIF A where A.MUS_K_ISIM = '" + hesapNo + "'";
SqlCommand cmd = new SqlCommand(query, myConnection);
if (DropDownList1.SelectedValue != "0" && DropDownList2.SelectedValue != "0")
{
Add.Enabled = true;
Label1.Text = cmd.ExecuteScalar().ToString();
}
else
{
Add.Enabled = false;
}
Label1.Visible = false;
myConnection.Close();
}
I just calculating HESAP with this code.
And my ADD button click function is;
protected void Add_Click(object sender, EventArgs e)
{
try
{
string strConnectionString = ConfigurationManager.ConnectionStrings["SqlServerCstr"].ConnectionString;
SqlConnection myConnection = new SqlConnection(strConnectionString);
myConnection.Open();
string hesap = Label1.Text;
string musteriadi = DropDownList1.SelectedItem.Value;
string avukat = DropDownList2.SelectedItem.Value;
SqlCommand cmd = new SqlCommand("INSERT INTO AVUKAT VALUES (#MUSTERI, #AVUKAT, #HESAP)", myConnection);
cmd.Parameters.AddWithValue("#HESAP", hesap);
cmd.Parameters.AddWithValue("#MUSTERI", musteriadi);
cmd.Parameters.AddWithValue("#AVUKAT", avukat);
cmd.Connection = myConnection;
SqlDataReader dr = cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection);
Response.Redirect(Request.Url.ToString());
myConnection.Close();
}
catch (Exception)
{
ScriptManager.RegisterClientScriptBlock(this, this.GetType(), " ", "alert('Bu Müşteri Zaten Mevcut!')", true);
}
}
The reason use try catch , if anybody try to add add with same HESAP (int) value for the MUSTERI i want show an error message and don't add the table.
But when i try to add same MUSTERI (also same HESAP) adding same MUSTERI with HESAP=0 value.
How can i prevent this situation? I select HESAP column is Primary KEY, but still add same MUSTERI.
There's nothing too obvious here that explains the behaviour you're seeing. The most likely problem really is that the value of Label1.Text is 0 before the insert is executed, maybe set somewhere else in the ASP.NET page lifecycle. To make sure add a line of code after hesap is initialised in Add_Click like...
Response.Write("<strong>hesap == " + hesap + "</strong>");
...and comment out the Response.Redirect so you can see the output.
There are also some improvements you can make to the code to make problems less likely to occur.
It's really important that you sanitise the input to avoid SQL injection. Hopefully you're already doing this elsewhere that's not shown in your code snippet. If you don't know what this is then there's heaps of questions about it here on SO.
Also, you're not doing a query for the purpose of retrieving any rows, so use ExecuteNonQuery. So I'd also replace this line...
SqlDataReader dr = cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection);
...with...
int numberOfRows = cmd.ExecuteNonQuery();
Then check the value of ExecuteNonQuery to ensure numberOfRows == 1 so you know something actually happened.
You should also wrap your SqlConnection and SqlCommand initialisers with using statements. This means that they will automatically be disposed even if something goes wrong. This will prevent memory issues and problems with connections being left open.
Finally, let the exception value flow through into the catch statement by changing that line to catch (Exception ex). Output the exception using ex.ToString() to see all of its details. Right now you don't know what might have gone wrong if an exception occurs.
HESAP is the primary key. However, does MUSTERI also have a Unique constraint which prevents someone from entering two MUSTERI values? That would at least prevent the data from getting into the database. So something like:
Alter Table AVUKAT Add Constraint UC_AVUKAT Unique ( MUSTERI )
Is there a CHECK constraint on HESAP which requires that the value be greater than zero? So something like:
Alter Table AVUKAT Add Constraint CK_AVUKAT_HESAP Check ( HESAP > 0 )
It should be noted that MySQL will ignore Check constraints. Thus, you would need to enforce this rule in a Trigger. However, many database systems such as SQL Server, Oracle, Postgres, Informix and others will enforce check constraints.
I would make the following revisions
I would alter the query to check for whether the value exists.
I would incorporate the using statement to ensure that my objects were disposed.
I would use ExecuteNonQuery and use the number of rows returned to determine if query did not insert anything rather than implementing a global catch-all. Unless you know exactly which error you expect, you should not use Catch ( Exception ) to catch any exception no matter the type.
protected void Add_Click(object sender, EventArgs e)
{
string strConnectionString = ConfigurationManager.ConnectionStrings["SqlServerCstr"].ConnectionString;
using( SqlConnection myConnection = new SqlConnection(strConnectionString) )
{
myConnection.Open();
string hesap = Label1.Text;
string musteriadi = DropDownList1.SelectedItem.Value;
string avukat = DropDownList2.SelectedItem.Value;
string sql = #"INSERT INTO AVUKAT( MUSTERI, AVUKAT, HESAP)
Select #MUSTERI, #AVUKAT, #HESAP
From ( Select 1 As Value ) As Z
Where Not Exists (
Select 1
From AVUKAT As T1
Where T1.HESAP = #HESAP
)";
using ( SqlCommand cmd = new SqlCommand(sql, myConnection) )
{
cmd.Parameters.AddWithValue("#HESAP", hesap);
cmd.Parameters.AddWithValue("#MUSTERI", musteriadi);
cmd.Parameters.AddWithValue("#AVUKAT", avukat);
cmd.Connection = myConnection;
int rowsAffected = cmd.ExecuteNonQuery();
if ( rowsAffected = 0 )
// tell user that ID exists and their data couldn't be inserted.
Response.Redirect(Request.Url.ToString());
myConnection.Close();
}
}
}
When you eliminate the impossible, whatever remains, however improbable, must be the truth.
If the HESAP value being inserted is zero, then Label1.Text must contain a zero when the Add_Click event is fired. Looking at your DropDown event handler, there are a couple of items of note.
If HESAP is supposed to be an integer, you should verify that it is an integer using int.TryParse.
The query should be parameterized. Even the contents of a DropDownList should be considred user input.
As before, it is best to incorporate the using construct.
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
int avukat;
int hesapNo;
bool enabled = int.TryParse( DropDownList1.SelectedItem.Value, out hesapNo )
&& int.TryParse( DropDownList2.SelectedItem.Value, out avukat )
&& hesapNo != 0
&& avukat != 0;
if ( enabled )
{
string strConnectionString = ConfigurationManager.ConnectionStrings["SqlServerCstr"].ConnectionString;
using( SqlConnection myConnection = new SqlConnection(strConnectionString) )
{
myConnection.Open();
string query = #"Select A.HESAP_NO
From YAZ..MARDATA.S_TEKLIF A
Where A.MUS_K_ISIM = #HesapNo"
using( SqlCommand cmd = new SqlCommand(query, myConnection) )
{
cmd.AddParameterWithValue( "#HesapNo", hesapNo );
Label1.Text = cmd.ExecuteScalar().ToString();
}
}
}
Add.Enabled = enabled;
Label1.Visible = false;
}
If you add the CHECK constraint I mentioned at the top, then the code will error on insert and the bad row will not get into the database. That should lead you back to the DataSource for DropDownList1. It would appear that its SelectedValue is being returned as zero. That would imply that source that populates DropDownList1 is pushing a value with zero in it. What is the source that populates DropDownList1?
Hi soner
To insert record in database we have call cmd.executenonreader() methods
I think that is problem please chek it & let me know.
Maybe you should try to insert a sample data directly to your database and try to test adding same MUSTERI and HESAP to the table. You should get an error.
And i think you should modify your query for inserting data at Add_Click
SqlCommand cmd = new SqlCommand("INSERT INTO AVUKAT VALUES (#MUSTERI, #AVUKAT, #HESAP)", myConnection);
it should be:
SqlCommand cmd = new SqlCommand("INSERT INTO AVUKAT (MUSTERI, AVUKAT, HESAP) VALUES (#MUSTERI, #AVUKAT, #HESAP)", myConnection);
Hope this helps
Without looking at your database schema, it's difficult to make any kind of real guess about what's going on here, but I might propose the following.
Does your database have unique indexes set up for the two values that you don't want to duplicate?
Is your database table set up so that primary keys are auto-generated, or are you manually managing primary keys?
Are any triggers causing the issue?
Are you certain that the code responsible for displaying the primary key column is retrieving it correctly in all scenarios?
Has the insert actually occurred? If the insert hasn't occurred, you're seeing the default value for integral values, which would be zero.
My next step would be to fire up profiler and find out what your application is ACTUALLY sending to SQL Server. Make sure the values coming in are what you expect them to be, then execute the query directly in SSMS/QA to make sure it behaves as expected.
I'm with Alex in that the culprit is probably an unexpected value in your label. Find out for sure what SQL Server is seeing so you know which value needs more attention throughout the page life cycle.
While trying to add the duplicate record, are you selecting value in both the drop-downs? I can make a wild guess that your second drop-down for AVUKAT is not selected and hence your Label1.Text is set to null resulting in 0 being inserted for primary key.
If error is in add button event, then the evil is Response.Redirect(Request.Url.ToString()); swap the connection.close() and response.redirect. because after page redirection the myconnection object is lost.
That should be this manner
myconnection.close();
Response.redirect("url",false);
i think it will work..

Categories