Oracle Data Reader Issue

Topics: Data Access Application Block
Feb 27, 2007 at 5:13 PM
Using the data application block, I can do this:

SqlDatabase sqlDatabase = new SqlDatabase("My connection String Info");
SqlDataReader reader = (SqlDataReader)sqlDatabase.ExecuteReader("StoredProc", new object[] { id});
if (reader.HasRows)
{
//Do Stuff
}


However if I try to do the same thing with Oracle it Fails
OracleDatabase oracleDatabase = new oracleDatabase("My connection String Info");
OracleDataReader reader = (OracleDataReader)sqlDatabase.ExecuteReader("StoredProc", new object[] { id });
if (reader.HasRows)
{
//Do Stuff
}


The line to set the reader errors with the following:
Unable to cast object of type 'Microsoft.Practices.EnterpriseLibrary.Data.Oracle.OracleDataReaderWrapper' to type 'System.Data.OracleClient.OracleDataReader'.

I know that reader.Read() will let me know if there is a line to read. However there are times it is desirable not to advance the cursor, only to know if there is data. The Oracle Data Reader supports this. Sql server supports this.

What is the purpose of returning an OracleDataReaderWrapper and marking it internal so that there isn't any way to get at this property? Is there a work around?
Feb 28, 2007 at 3:03 PM
I don't think the intention was to return the OracleDataReaderWrapper. I think the code meant to return an OracleDataReader which is why you are getting a cast error.

I don't have Oracle to test this so I can only speculate that it may be a bug. I noticed the following code in the OracleDatabase Class:

public override IDataReader ExecuteReader(DbCommand command)
{
	PrepareCWRefCursor(command);
	return new OracleDataReaderWrapper((OracleDataReader)base.ExecuteReader(command));
}

public static explicit operator OracleDataReader(OracleDataReaderWrapper oracleDataReaderWrapper)
{
    return oracleDataReaderWrapper.InnerReader;
}

My guess is that either the EntLib Team meant to create an implicit operator to cast from OracleDataReaderWrapper to OracleDataReader or they forgot to explicitly cast it during the return above.

I think the error is probably occurring at the code above, but again, I cannot test it to verify.

I will add it as an issue and see if it is indeed a bug or perhaps something else.

Regards,

Dave

_______________________

David Hayden
Microsoft MVP C#
Feb 28, 2007 at 3:14 PM
On another note, this code should work:

IDataReader reader = oracleDatabase.ExecuteReader("StoredProc", new object[] { id });

I still think you have a point, however.

Regards,

Dave

____________________

David Hayden
Microsoft MVP C#
Feb 28, 2007 at 3:40 PM
The more I look at it, however, the code should work.

ExecuteReader is returning an OracleDataReaderWrapper which implements IDataReader.

You are explicitly casting it to OracleDataReader which means the explicit operator will return the Inner OracleDataReader Class.

I would think a cast error would not happen.

Too hard to say without being able to test it, but maybe someone who has Oracle can shed some light on the matter.

Regards,

Dave

________________________

David Hayden
Microsoft MVP C#
Feb 28, 2007 at 4:16 PM
I can cast to IDataReader, However IDataReader does not have the HasRows property.

This is how I normally use the oracle execute reader. However I have a case where I need to know if there is data first.

The fact is the error does occur. The only work around I can think of is to make two calls, first call does a count of the rows that would be returned by the query and stores that in a variable and then making the other call that returns all rows using the IDataReader if this count > 0. Not horribly expensive, but unnecessary considering that the information is right there and I just can't get to it.
Feb 28, 2007 at 5:54 PM
I don't disagree that the error is occuring and I think what you are asking for is genuine.

I just can't personally test it, so I don't know where the error is occurring. It doesn't look like the EntLib Team was trying to keep you from casting it to OracleDataReader based on the source code.

It may be a bug, it could be something in your code, or it could be that we are not using it as expected or correctly. Based on the code you wrote above, I can tell this isn't actual code you ran because you accidentally typed in sqlDatabase here when I know you meant oracleDatabase:

OracleDataReader reader = (OracleDataReader)sqlDatabase.ExecuteReader("StoredProc", new object[] { id });

Of course, if this is the actual code, your problem might be because you used sqlDatabase instead of oracleDatabase in you statement above :)

If I had Oracle, I could figure it out pretty quickly. But since I don't, perhaps someone else can respond.

Regards,

Dave

________________________

David Hayden
Microsoft MVP C#
Feb 28, 2007 at 6:50 PM
you caught me. yeah that is not the acutal code, was trying to clean up/simplify for posting. Stored Procedure name isn't StoredProc either.

However the error message showen above was copied/pasted directly from the exception as it occured. Had I actually been running it against a sql database at the time the excpetion would have been something like "Can't cast type SqlDataReader to OracleDataReader". Even on a slow day I could have figured that one out.

I'm not using oracle by my choice....
Oct 18, 2007 at 9:15 PM
Am trying to understand the EntLib code. We need to use it for Oracle db.
What exactly is the purpose of OracleDataReaderWrapper class?

Would just this not suffice - return (OracleDataReader)base.ExecuteReader(command, transaction); ?

Why - return new OracleDataReaderWrapper((OracleDataReader)base.ExecuteReader(command, transaction));
Oct 22, 2007 at 11:43 PM
Hi,

The OracleDataReaderWrapper does some useful type conversion for booleans and Guids, among others.

Fernando
Feb 13, 2008 at 8:08 PM
What did you do to resolve this problem, I am running into the same thing.

return (OracleDataReader) DataConnectivity.EmsDb.ExecuteReader(CommandType.Text, sql.ToString());

Throws Exception:
Unable to cast object of type 'Microsoft.Practices.EnterpriseLibrary.Data.Oracle.OracleDataReaderWrapper' to type 'System.Data.OracleClient.OracleDataReader'.
Feb 14, 2008 at 3:40 PM
Bump, need this resolved...
Feb 15, 2008 at 4:30 PM
1 . The class OracleDataReaderWrapper is internal, so the explicit cast operator specified on the class is pretty much useless for the users.

2. Even if you get access to explicit cast, the statement
OracleDataReader reader = (OracleDataReader)OracleDatabase.ExecuteReader(storeproc)
should infact be
OracleDataReader reader = (OracleDataReader)(OracleDataReaderWrapper)OracleDatabase.ExecuteReader(storeproc).
as, you need explicitly cast IDataReader to OracleDataReaderWrapper, before you can make use of the explicit cast between OracleDataReader and OracleDataReaderWrapper class.

So, if the class OracleDataReaderWrapper is made public, then
OracleDataReader reader = (OracleDataReader)(OracleDataReaderWrapper)OracleDatabase.ExecuteReader(storeproc).
would help you get to OracleDataReader


Neo.
Feb 15, 2008 at 4:42 PM
The only logical reason that i could think of, for creating a OracleDatarReaderWrapper out of OracleDataReader in Database.ExecuteReader() , and then keeping oracleDataReaderWrapper as an internal type, is to prevent users from using OracleDatareader, or rather to encourage users to use only IDatareader

I couldnt find a reason why OracleDataReaderWrapper cant be a public sealed class ? Can someone in entlib team, shed some light here?

thanks. Neo.

Feb 18, 2008 at 2:09 PM
Edited Feb 18, 2008 at 2:38 PM
Why can't I use the OracleDataReaderWrapper class's special functionality in my project. Visual Studio knows that its returning an OracleDataReaderWrapper class, but I can't define a variable as such so I automatically loose the .InnerReader functionality?

Yes, can someone from the EntLib team advise on the best action to take? I see there are some custom fuctionality coded in the OracleDataReaderWrapper class, but since its marked as Internal, I can't get access to it.

I'd like to use either the OracleDataReader or OracleDataReaderWrapper. Any suggestions?