Hello and thanks for reading. We have a Filemaker database that we would like to read using System.Database.ODBC - We successfully connect and also, if we want to update, delete, or insert, it works fine using command.ExecuteNonQuery(), the problem arises when we try to read data, in other words, when we try to get a recordset... I did notice it reads successfully from the database using command.ExecuteReader(), the problem arises when it tries to loop through the columns and rows, specifically when it tries to get the column name, datatype, etc... in other words, the metadata.
for example, in the following query: "SELECT company FROM AC__Account WHERE ""Account Id"" = 30" it should return a single field, in this case "company", and a single record, the #30.
When I use command.ExecuteReader() and check for reader.FieldCount, it returns correctly 1, if I check for rows using reader.HasRows it returns true, this is how I know, it received the data correctly.
Now, if I try to inspect the reader object by adding a breakpoint, and the ResultView (in this case, an Enumerable), instead of an enumerable I found an error as follow:
and inspecting the full StackTrace this is what I get
at System.Data.Odbc.OdbcConnection.HandleError(OdbcHandle hrHandle, RetCode retcode) at System.Data.Odbc.OdbcDataReader.GetColAttributeStr(Int32 i, SQL_DESC v3FieldId, SQL_COLUMN v2FieldId, HANDLER handler) at System.Data.Odbc.OdbcDataReader.GetName(Int32 i) at System.Data.Common.DbEnumerator.BuildSchemaInfo() at System.Data.Common.DbEnumerator.MoveNext() at System.Linq.SystemCore_EnumerableDebugView.get_Items()
Is there a way to bypass Microsoft to get the metadata? or am I missing something? Please help, please check my code.
using (OdbcConnection connection = new OdbcConnection(Conf.GetSection("ConnectionStrings:FilemakerPre1").Value))
{
string queryString = #"SELECT company FROM AC__Account WHERE ""Account Id"" = 30";
OdbcCommand command = new OdbcCommand(queryString, connection);
connection.Open();
var reader = command.ExecuteReader();
Console.WriteLine($"Field count: {reader.FieldCount}");
Console.WriteLine($"Any rows?: {reader.HasRows}");
while (reader.Read())
{
Console.WriteLine(reader[0]);
}
}
Related
I wrote the following code for connecting to an oracle database with my c# code:
private string GenerateConnectionString()
{
return "Data Source=( DESCRIPTION = ( ADDRESS_LIST = ( ADDRESS = ( PROTOCOL = TCP )( HOST = 192.168.X.XXX)( PORT = 1521 ) ) )( CONNECT_DATA = ( SERVER = DEDICATED )( SERVICE_NAME = XXXX ) ) ); User Id= xxxxxx; Password = xxxxxx;";
}
private void button1_Click_1(object sender, EventArgs e)
{
try
{
using (OracleConnection connection = new OracleConnection(GenerateConnectionString()))
{
connection.Open();
lblState.Text = connection.State.ToString();
OracleCommand oc = connection.CreateCommand();
oc.CommandText = "INSERT INTO TABLE (NO1, NO2, NO3, NO4, NO5, NO6, NO7, NO8, NO9, NO10, NO11, NO12, DATE) VALUES(1,2,3,1,1,1,'{txb_Textbox1.Text}',5,0.5,10,11,12,TO_DATE('09.07.2020 16:24:00', 'DD.MM.YYYY HH24:MI:SS'))";
oc.ExecuteNonQuery();
}
}
catch (Exception ex)
{
MessageBox.Show( "Exception: " + ex.Message );
lblState.Text = ex.Message;
}
}
I also installed all the necessary drivers for connecting to the oracle database and added the System.Data.OracleClient.dll as a reference to my c# project and added the "oraocci19.dll" and "oraocci19d.dll" file to the project file. I also added the oracle client to the system environment variables under PATH. Furthermore, I declared using System.Data.OracleClient;at the beginning of my overall code.
Please don't tell me that I do not use the latest Oracle Data Access Components (ODACs). I know that. We have a very old Oracle Database and I like the idea that I only need to install a few oracle dll's for it to work.
I just don't know what to do and spent the whole Friday and the whole weekend researching so that I could write to the Oracle database. I hope that someone experienced recognizes the problem directly and can help me.
Thank you very much in advance! :) Best regards
Edit1: Maybe I should try the other Oracle Data Access Components (ODACs) and their dlls. But normally my dll files should also work. A colleague of mine used my ODAC Installation and he said everything worked with it. But, he only had to read data from an Oracle table and not write in one.
Edit2: I got the problem! I was able to find the solution. Their was a mistake in my Oracle Prompt in the string. The C# code was correct. Here on stackoverflow I have of course reformulated and generalized the Oracle prompt string because it contains trusted data. The error was in the Oracle Command. This thread can be closed. Pete -S- got the right answer!
You could try this:
//Do the insert
oc.CommandText = "INSERT INTO TABLE (NO1, NO2, NO3, NO4, NO5, NO6, NO7, NO8, NO9, NO10, NO11, NO12, DATE) VALUES(1,2,3,1,1,1,'{txb_Textbox1}',5,0.5,10,11,12,TO_DATE('09.07.2020 16:24:00', 'DD.MM.YYYY HH24:MI:SS'))";
oc.ExecuteNonQuery;
//Retrieve in a separate action (you have to update your command to SELECT from INSERT)
oc.CommandText = "SELECT * FROM TABLE"; Statement
OracleDataReader reader = oc.ExecuteReader();
Another thing you can look at, is the CommandBuilder; but, it's the easy way out then a good solution. You can then specify the SELECT and the command builder will create the INSERT, UPDATE and DELETE commands.
Other thoughts
I don't think you can bind a data reader to a .DataSource. You can load a data table from a data reader, see this example.
Here is more information on DataAdapters and DataReaders
To UPDATE/INSERT: use .ExecuteNonQuery
To SELECT: there are different options, one is to build a DataTable via DataAdapaters and bind the data source using the data table.
You are doing it in the wrong order, you need to set the command text first and then execute the command (with ExecuteNonQuery() or ExecuteReader()):
OracleCommand oc = connection.CreateCommand();
oc.CommandText = "INSERT INTO TABLE (NO1, NO2, NO3, NO4, NO5, NO6, NO7, NO8, NO9, NO10, NO11, NO12, DATE) VALUES(1,2,3,1,1,1,'{txb_Textbox1}',5,0.5,10,11,12,TO_DATE('09.07.2020 16:24:00', 'DD.MM.YYYY HH24:MI:SS'))";
OracleDataReader reader = oc.ExecuteReader();
Here is a sample code of using the SqlDataReader:
// Working with SQLServer and C#
// Retrieve all rows
cmd.CommandText = "SELECT some_field FROM data";
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine(reader.GetString(0));
}
}
EDIT :
I mean I want to understand whether there is the same mechanism when retrieving data from database in a while-loop (in case of SqlDataReader) as it does when working with the SQLite.
// working with SQLite and Java
if (cursor.moveToFirst()) {
do {
String data = cursor.getString(cursor.getColumnIndex("data"));
// do what ever you want here
} while(cursor.moveToNext());
}
cursor.close();
No, there's no cursor on the server side unless your command is calling a stored procedure that uses a cursor. The server is returning a plain-vanilla SQL result set, one row at a time, when you use a SqlDataReader. Obviously, the data's got to be somewhere before you can read it, and that place would be buffer(s) that SQL Server and the drivers manage.
If you were to push this into using something like a Dataset, then all the rows would be in RAM at once.
While you use cursor which returns many dbsets you can obtain many result sets like that:
while (oSqlDataReader.HasRows)
{
while (oSqlDataReader.Read())
{
// oSqlDataReader.Getdata...
}
oSqlDataReader.NextResult();
}
I am try to display data from a database. However even though data exists in the database no records are being returned.
If run the following query:
select Id, Movie_Name from [MovieTable] where Movie_Name like '10,000 BC'
I get being returned:
However when running a similar query in c# nothing seems to be being returned. My code is as follows:
try
{
string query = "select * from [MovieTable] where Movie_Name like #MovieName";
string movieName = "10,000 BC"
using (SqlConnection sconnection = new SqlConnection(#"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=E:\Application\ApplicationDatabase.mdf;Integrated Security=True");)
using (SqlCommand command = new SqlCommand(query, sconnection))
{
sconnection.Open();
command.Parameters.AddWithValue("#MovieName", movieName);
using (SqlDataReader oReader = command.ExecuteReader())
{
if (oReader != null)
{
while (oReader.Read())
{
MessageBox.Show(oReader["Movie_Name"].ToString());
}
}
}
}
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
The message box never appears. Adding a third message box just above oReader.Read() displays the message "Invalid attempt to read when no data is present". Is there something i am missing?
Your code runs fine for me, with little adaptions though.
You query the value of the attribute 'Year' which is not present in the table and in your first query:
oReader.GetOrdinal("Year")
That causes an exception in the sample.
Single Quotes are not needed since you are using a parametrized query.
For debugging calls to System.Diagnostics.Debug.WriteLine() are more useful than MessageBoxes
Issue was with the data itself. Field was incorrectly set as type "Text". I altered the fields data type to "nvarchar(MAX)". It also mean't the query could be altered to:
"select * from [MovieTable] where Movie_Name = #MovieName"
I've got an application that, when a button is clicked, reads an access database for products and lists them in a listbox and dataGridView. The connection command text is northwind_command.CommandText = "SELECT ProductName, UnitPrice FROM Products WHERE UnitPrice > (#price_greater_than)";
On the first click the program will work, but when the button is clicked a second time an exception is thrown. As this thrown exception causes the data reader to "crash", the third click will work as if it was the first. The fourth click will throw the same exception. If I had to guess, I'd say that the the datareader isn't closing properly, but it should be. Here is the code for that part of the program:
northwind_connection.ConnectionString = #"Provider=Microsoft.Jet.OLEDB.4.0;Data Source='U:\Programming\C#\Week 13\Exercises\ExerciseA1\bin\northwind.mdb';Persist Security Info=True";
northwind_command.Connection = northwind_connection; // connects the command to the connection.
northwind_command.CommandText = "SELECT ProductName, UnitPrice FROM Products WHERE UnitPrice > (#price_greater_than)"; // sets the query used by this command.
northwind_command.Parameters.AddWithValue("#price_greater_than", price_greater_than);
try
{
northwind_connection.Open(); // opens the connection.
northwind_reader = northwind_command.ExecuteReader(); // reads the data from the connection while executing the command.
dataGridView1.Columns.Add("ProductName", "Product Name");
dataGridView1.Columns.Add("UnitPrice", "Product Price");
while (northwind_reader.Read())
{
dataGridView1.Rows.Add(northwind_reader["ProductName"], northwind_reader["UnitPrice"]);
listBox1.Items.Add(northwind_reader["ProductName"] + "\t" + northwind_reader["UnitPrice"]);
}
}catch(Exception mistake)
{
MessageBox.Show(mistake.ToString());
}
northwind_connection.Close();
EDIT: I've solved the issue with some help, but would like to figure out why it was happening in the first place. The offending line was northwind_command.Parameters.AddWithValue("#price_greater_than", price_greater_than);. The line above that one was modified to: northwind_command.CommandText = "SELECT ProductName, UnitPrice FROM Products WHERE UnitPrice > " + price_greater_than; and the program now works correctly.
That method was causing the exception to be thrown, which can be seen below:
I checked the exception message and line 50 contains this code: northwind_reader = northwind_command.ExecuteReader();, which confirms that the AddwithValue method was causing the error.
My bet is that something is not getting disposed of properly. Try modifying your code to use using statements:
using(var northwindConnection = new OleDbConnection())
{
//Set your connection info
using(var northwindCommand = northwindConnection.CreateCommand())
{
//Set your command info
try
{
// Open your connection and any other things
// needed before executing your reader
using(var reader = northwindCommand.ExecuteReader()){
//Do what you need with your reader
}
}
catch(Exception mistake)
{
MessageBox.Show(mistake.ToString());
}
}
}
When a class implements IDisposable, you really should wrap that in a using statement. Doing so will make sure that all resources are properly disposed. In the case of database connections, this will make sure that your connection is closed, so no need to call myConn.Close().
Another things that might be causing issues is that you are adding columns to dataGridView1 every time the button is clicked.
Edit:
Since you found the problem is with AddWithValue, let me add this:
In past experience, I have had issues using the #paramName syntax with OleDbCommand. Try using ?paramNam syntax instead. I have also had issues if the name is to long, so try shortening it.
You should use Paramaters.Add(string, OleDbType).Value = value instead of Paramaters.AddWithValue(string, value). The reason being is that AddWithValue has to interpret the type of the column, and it can sometimes get it wrong.
Add northwind_reader.Close() at the end of the while loop.
You need to close reader before use it again.
example:
while (reader.Read())
{
string value = reader.GetValue(0).tostring();
}
reader.Close();
in your case is northwind_command.close()
Here's the crux of it:
I have this script which gave me absolutely no problems until after I ran it through a performance test, and now its' constantly showing me the same error during debug whenever I try to run it:
using (OracleConnection con = new OracleConnection())
{
//Connect to OracleDB and retreive the first valid, unused SRVID//
con.ConnectionString = #"Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=myhostip)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=MyServerNAme)));User Id=MyUSer;Password=MyPAssword";
OracleCommand command = new OracleCommand("SELECT MASK_GUID(SWAP_GUID(SRVID)) FROM MYTable WHERE USED=0 AND ROWNUM = 1", con);
con.Open();
OracleDataReader reader = command.ExecuteReader();
reader.Read();
ServerID = reader.GetString(0);
reader.Close();
//update SRVID in DB as used so further users will not select it
command.CommandText = "UPDATE MyTable SET USED=1 WHERE SRVID = FIX_GUID('"+ ServerID+"')";
command.Connection = con;
command.ExecuteNonQuery();
reader.Close();
reader.Dispose();
con.Close();
con.Dispose();
}
That's the code, here's what goes wrong:
on ServerID= reader.GetString(0) I receive the operation is not valid due to the current state of the object error. When glossing over reader in debug, I see that it has no data rows, which might explain the error (but that leads to...)
The query is fine. I run it locally on the database and it returns a valid value ( I copy-pasted it to be sure), so that's not the reason reader has no data.
This problem started during a performance test which ran this script about 800 times before this error started to appear constantly... The system which I tested still operates fine, even when performing actions that require access to the same database.
Debugger shows no other errors regarding this case... OR at all, for that matter.
Ideas?
You need to set the MaxHttpCollection property to a higher value.