AdsConnection throws EntryPointNotFoundException on second connection but works the first time - c#

I have a piece of code that I reuse that helps me connect to an adt database and read the data.
using Advantage.Data.Provider;
...
protected DataTable FillTable(string tableName)
{
DataTable table = new DataTable();
using (var conn = new AdsConnection(connectionString))
using (var adapter = new AdsDataAdapter())
using (var cmd = new AdsCommand())
{
cmd.Connection = conn;
cmd.CommandText = "select * from " + tableName;
adapter.SelectCommand = cmd;
conn.Open();
adapter.Fill(table);
conn.Close();
}
return table;
}
This code works perfectly the first time I go through it, but gives the following exception the second time I call it with a different table name.
System.EntryPointNotFoundException: 'Unable to find an entry point named 'AdsIsConnectionAlive' in DLL 'ace32.dll'.'
I would like an explanation.
I've tried to read up on this error, but all the possible scenario's I've found don't explain why it works the first time. They mention problems with the DLL like it being the wrong version or some incompatability with the .NET version, ...
If I change the order of the calls the code still fails on the second time, so I know the problem isn't with the name of the table or the way I call my code. The problem is probably with me not closing the connection correctly. I've tried adding more braces just to make sure that that part runs correctly and I've debugged to make sure that the first conn.Close(); is executed correctly.
I could place all my code within this code and only use one connection that I keep open as long as I need it. That would bypass my problem, but I would like to avoid that and to understand what I'm doing wrong.

This is most likely caused by loading an older version of ace32.dll from a newer version of the ado.net components. The AdsIsConnectionAlive was introduced in a later version of the DLL - not sure about the exact version probably 6.0 or later.
The first time the connection was made, the ado.net component knows that the connection was not alive so there was no need to call the IsAlive entry point. The second time around, since there was already a connection made to the same connection path, it would try to reuse it by checking to see if it is still alive. I think that there is a way to disable the connection caching but do not remember the detail. A better solution would be to make sure that the advantage DLLs are matching version.

Related

Oracle Managed DataAccess connection object is keeping the connection open

I'm using Oracle.ManagedDataAccess Nuget package version 18.3.0. I tried many things. I tried to dispose everything I can think of, even oracle parameters objects. And wrapped everything inside a using block but to no avail. The only thing that actually worked for me is that the commented line OracleConnection.ClearPool(oracle);. Is this a bug, or some configuration related issue, or am I misunderstand things here? Also, I tried to remove the reference of Oracle.ManagedDataAccess and replaced it with a reference to System.Data.OracleClient and that actually worked for me. It automatically closed the connection, so no connection left with "In-Active" status. The code below I moved it into a simple, single button, Windows Forms application to make 100% sure nothing is interfering and the problem still occurring.
using (var oracle = new OracleConnection("Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=myhost)(PORT=SomePortHere))(CONNECT_DATA=(SERVER=SHARED)(SERVICE_NAME=anotherHost)))", new OracleCredential(userName,password)))
{
oracle.Open();
using (var command = new OracleCommand())
{
var query = "SELECT x from y where z=:param1";
command.Connection = oracle;
command.CommandText = query;
command.CommandType = System.Data.CommandType.Text;
var param1 = new OracleParameter(":param1", xyz);
command.Parameters.Add(param1);
using (var reader = command.ExecuteReader())
{
if (reader.Read())
{
//read the data from the reader
}
}
param1.Dispose();
}
//If this line is commented, there will be a connection left open, with InActive status
//OracleConnection.ClearPool(oracle);
}
password.Dispose();
return myData;
And this is an image to show the opened connection through Toad.
Of course, for each click to that button, the code above will execute and a new session will remain open, until what you see in the image.
The name "TheTesterOfAllTests.exe" is the Windows Forms app.
Is this a configuration problem?
Is there any way to solve this issue other than using ClearPool method? Because it affects the performance of the app.
P.S. The application that is originally using the code above is a WCF Service that is consumed by a Web application.
P.S. 2 There is some kind of memory leakage, with each click to that button the memory usage increases
I ran into the same problem.
I solved it by changing the initialization of the OracleConnection.
from
var con = new OracleConnection(
"Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=myhost)(PORT=SomePortHere))(CONNECT_DATA=(SERVER=SHARED)(SERVICE_NAME=anotherHost)))",
new OracleCredential(userName,password));
to
var con = new OracleConnection(
"USER ID=myuser;PASSWORD=mypwd;Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=myhost)(PORT=SomePortHere))(CONNECT_DATA=(SERVER=SHARED)(SERVICE_NAME=anotherHost)))");
To me, this different behavior looks like a bug.
As a result, i can no longer use OracleCredential and must store the password as a string. That's okay for me.
remark: SecureString shouldn't be used
It turns out the problem is in the way internally oracle creates connection, since for each newly created OracleConnection object, a new Connection is added to the Connection pool. I counted 91 connection entry in the connection pool.
The solution was to use one OracleConnection instance for each request "Per Request Scope". I implemented that by using a simple generic IDatabase<TConnection> interface with one TConnection GetConnection<TConnection>() method and of course for each method that will be called on that same request's instance, a pair of Open/Close call will take place so we don't keep the connection open the whole time.
Regarding the memory leak, I'm still not able to 100% confirm this, but when I used the Oracle.DataAccess.Client library instead of Oracle.ManagedDataAccess the memory usage reduced dramatically. So, I switched back to Oracle.DataAccess.Client.
P.S. I will update this answer in case of new information regarding these two issues, and contributions are very welcome, maybe I misunderstand something regarding how Oracle deals with the database connection.

Oracle InvalidOperationException - When trying to select from a table

I've got a parameters table where I've got a parameter to say whether my program should run, I'm trying to get this value to check for a function.
Here is the function
private static bool shouldRun()
{
OracleCommand c = conn.CreateCommand();
c.CommandText = "select value from parameters where lower(name) = lower('valuetocheck')"; // this one doesn't work
//c.CommandText = "select 'Y' from dual"; - This one works
c.CommandType = System.Data.CommandType.Text;
OracleDataReader dr = c.ExecuteReader();
dr.Read();
string s = dr.GetString(0); // exception on this line
return false;
}
The additional information is below:
Invalid operation on a closed object
I've tried selecting from dual, as you can see above, which works perfectly fine, but when I try to run the actual query it doesn't like it. I've checked the query in SQL Developer and it works fine.
I've had a look around SO and other websites and the only information I could get on this issue was that the command wasn't associated with a connection, which as you can see above it is.
I've also tried just doing
OracleCommand c;
c.Connection = conn;
Which also doesn't work.
Any insight into this would be great, thanks!
I had the same issue recently. I got the "Invalid Operation on a closed object" but when I debug the code, it was the OracleDataReader that was closed and not the OracleConnection. My problem was the query retuned an empty response and the DataReader closes itself if there is no data. So my resolution was simply checking if the data reader have any rows by adding the following..
dro.Read();
if (dro.HasRows)
{
//Do your
}
I hope it helps someone.
When Oracle gives this error - "Invalid Operation on a closed object", more often than not, what actually happens is that the user does not have access privileges to the objects they are trying to access in the database. Check your connection string and make absolutely sure that the user listed in that connection string does have privileges to the objects in your query - in this case, read access to the Parameters table.
NOTE: While the information in this answer does not directly fix the issue in the original question, I found this question and the other answers very helpful in pinpointing the solution to another related scenario.
When changing from the unmanaged Oracle.DataAccess library to the managed Oracle.ManagedDataAccess library, we found a very tricky difference. Apparently, with the unmanaged library, the dr.Read() call is not required for the fetch to happen, but it most definitely is required with the managed library.
After switching to the managed library, all of our calls constructed similar to the example in the question needed to have dr.Read() added before trying to get any data out of the dr object, otherwise we would get the same "Invalid operation on a closed object" message.
Check your connection String
Replace conn.State == ConnectionState.Closed with conn.State != ConnectionState.open
For me the issue was in this part of my code -
(dt is the object of DataTable in the below code samples)
using (var reader = lSqlCommand.ExecuteReader())
{
while (reader.Read())
{
dt.Load(reader);
}
}
When I removed the while part it got resolved. The working part now is like -
using (var reader = lSqlCommand.ExecuteReader())
{
dt.Load(reader);
}

INSERT INTO command not working

Before I start, I'll let you know that I tried everything that has already been suggested on previous questions and other websites before I considered posting a question myself. As it happens, nothing seems to work and I'm just about fed up with this.
As some background information, this is for my Computing A2 project, so I'm kind of stuck for time now - i.e. I can't be changing loads of my code ideally.
Anyway, onto the issue...
I'm using SQLCe in my code to read from various tables and write to one. So far, the code for reading from the tables works fine, so that's any connection issues out the way first. The piece of code I am struggling with is as follows:
string connectionString = Properties.Settings.Default.BookingSystemDatabaseConnectionString;
using (SqlCeConnection myConnection = new SqlCeConnection(connectionString))
{
myConnection.Open();
try
{
string commandStr = "INSERT INTO bookings(username, room, time) VALUES(#username, #room, #time)";
SqlCeCommand myCommand = new SqlCeCommand(commandStr);
//Passes parameters into SQL command.
myCommand.Parameters.AddWithValue("username", StaticUser.StudentUser.username);
myCommand.Parameters.AddWithValue("room", roomBox.Text);
myCommand.Parameters.AddWithValue("time", timeBox.Text);
//Executes SQL command. Returns the number of affected rows (unecessary for my purposes; a bi-product if you will).
myCommand.ExecuteNonQuery();
}
catch
{
System.Windows.Forms.MessageBox.Show("Could not write new booking to database. This is likely because the database cannot be reached.", "Error");
Program.AccessError = true;
}
myConnection.Close();
}
This is just one of the many ways I have tried to combat the issue I am having. I have also explored:
myCommand.Parameters.Add(new SqlCeParameter("username", StaticUser.StudentUser.username));
to pass the parameters...and another method which escapes me now (using ".Value = StaticUser.StudentUser.username" I think). Furthermore, I have tried using a 'using' statement for the command to save me closing the connection myself (I will probably end up using a solution that uses 'using'). Finally (albeit this isn't a chronological recollection), I tried:
SqlCeCommand myCommand = new SqlCeCommand("INSERT INTO bookings(username, room, time) VALUES(#username, #room, #time)", myConnection)
Again, of course, to no avail.
To highlight the actual symptoms of the issue I am having: The code appears to run fine; stepping through the full method I have pasted above shows that no error is being caught (of course, the message box does not appear - I realised afterwards that stepping through was arguably an unnecessary procedure) and in the other methods I have touched on, the same thing happens. The issue, then, is that the table 'bookings' is not actually being updated.
So, my question, why?
I didn't do the obvious and check the Debug folder for an updated database.
Look for a copy of the database file in your bin/debug folder.
Use full path in connection string, and preferably do not include the sdf file in your project (or at least set build action to None)
i think you are not defining a connection for the command
try
mycommand.connection = connectiostring;

"table or view does not exist", but only sometimes

A SQL select statement gets run when a user presses a button on my website, and I do this:
connection = new OleDbConnection();
connection.ConnectionString = [connection string];
connection.Open();
cmd = profile.Execute(mySQLStatement);
da = new OleDbDataAdapter(cmd);
table = new DataTable();
da.Fill(table);
90% of the time, this works just fine. But every once in a while, I get the OleDbException table or view does not exist on the line da.Fill(table). There doesn't seem to be a pattern of when this works and when it doesn't, though it's more likely to not work when the site isn't used for a minute or two... Like the session might be expiring. But the rest of the website (that does not require this database) works.
Any ideas of what might be happening or how to fix it?
I have not found a solution. As a temporary fix, whenever this happens, I just re-start the page.
Sometimes the content of mySqlStatement is not exactly correct, maybe?
Trap the exception dump mySqlStatement to a logfile (with date and time this happened), and then throw.

Beginner requests Help with Mysql and C#

I'm trying to build a program that uses a C# to work with a MySQL DB. I get the C# syntax, and can write the language, but I don't have much experience with the libraries, and I feel a bit lost.
Could someone post examples of how a program would be built (in technical terms, syntax would be nice, but pseudo code is fine, too)?
I understand the theory of how it works, but need a hands on approach to it.
Thank you.
EDIT
I forgot to add that I want to learn how to do it with the .NET v.2.0 framework / VS2005 / MySQL v5.0 combination.
EDIT # 2
2.0 .NET will only be supported. =)
Here is tutorial for Entity Framework + MySQL.
There are lots of other ways to operate with DB, depending on what you need:
If you need execute raw sql queries against DB - use OdbcConnection + OdbcCommand
Need to manipulate items in DB as objects - use ORM (EntityFramework, NHibernate, Linq2Sql)
Like old-style DB interop? - DataSets is your choice.
I really like EF. Easy thing to start with.
PS: And before mixing UI and DB-interop, please read about Separation of concerns. MVC is interesting to read about too. About "libraries": create another project in your solution and add DB-interop logics there. Don't mix it in one assembly, because when your project becomes bigger than "Hello DataBase!" application it will create a big mess in code and logics, really.
UPDATE:
Using VS2005 and .net 2.0 is mysterious idea, really. Lots of tools and assemblies where made since 2.0 release. Linq, Orm-s, etc. Live without them is hard and all the benefits of C# are lost. I highly recommend to use latest techniques, if there is no strict reasons to use 2.0.
If using SqlServer - ObdcCommand and OdbcConnection can be replaced to SqlCommand and SqlConnection. (thanks #Abe Miessler comment)
Here is an example swiped from MSDN:
public void InsertRow(string connectionString, string insertSQL)
{
using (OdbcConnection connection =
new OdbcConnection(connectionString))
{
// The insertSQL string contains a SQL statement that
// inserts a new row in the source table.
OdbcCommand command = new OdbcCommand(insertSQL, connection);
// Open the connection and execute the insert command.
try
{
connection.Open();
command.ExecuteNonQuery();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
// The connection is automatically closed when the
// code exits the using block.
}
}
If you want to read records in a DB, look at this example:
public static void ReadData(string connectionString)
{
string queryString = "SELECT DISTINCT CustomerID FROM Orders";
using (OdbcConnection connection = new OdbcConnection(connectionString))
{
OdbcCommand command = new OdbcCommand(queryString, connection);
connection.Open();
// Execute the DataReader and access the data.
OdbcDataReader reader = command.ExecuteReader();
while (reader.Read())
{
Console.WriteLine("CustomerID={0}", reader[0]);
}
// Call Close when done reading.
reader.Close();
}
}
FYI i am just copy/pasting these directly from MSDN. I highly recommend reading over their documentation and looking at their examples if you are just getting started.
http://msdn.microsoft.com/en-us/library/system.data.odbc.odbcdatareader.aspx
Here is a blog post getting you started with MySql and C#.
http://blog.bobcravens.com/2010/06/the-repository-pattern-with-linq-to-fluent-nhibernate-and-mysql/
Hope that gets you started.
Bob

Categories

Resources