Database.ExecuteReader not virtual

Topics: Data Access Application Block
Feb 23, 2013 at 8:05 PM
Hi,

how comme the Database Object, not all functions are "virtual" ?

public IDataReader ExecuteReader(string storedProcedureName, params object[] parameterValues)

but most are ?

i.e.
public virtual object ExecuteScalar(string storedProcedureName, params object[] parameterValues)
Feb 23, 2013 at 11:31 PM
Edited May 1, 2013 at 9:43 PM
Why questions are usually hard to answer unless you were "in the room". Given that the Database class is probably at least 7 years old I'm not sure if an authoritative answer will be forthcoming. But maybe someone out there has some insight? :)

In terms of the specific example you gave (public IDataReader ExecuteReader(string storedProcedureName, params object[] parameterValues) ), let's look at the code. The code for that overload of ExecuteReader is:
public IDataReader ExecuteReader(string storedProcedureName,
                                    params object[] parameterValues)
{
    using (DbCommand command = GetStoredProcCommand(storedProcedureName, parameterValues))
    {
        return ExecuteReader(command);
    }
}
So, yes, the method is not virtual but the only real functionality is actually in two other methods: GetStoredProcCommand and ExecuteReader. If we examine both of those methods we can see that they are both virtual so any classes that extend Database will be able to insert their own functionality to create the stored procedure command as well as determine how to create the IDataReader.

My guess as to why this method is not virtual is that it is basically a convenience method around core functionality implemented in other virtual methods. Could someone want to have different logic for this specific overload? I guess so but it seems unlikely (and probably not a good idea anyway IMO).

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to
Feb 24, 2013 at 12:48 AM
Thank you for your answer. I still would like to give you a context.

In the course of my work, I had to write a wrapper, SqlManager that uses a Database object. This to encapsulate repetive patterns to call 'repository' and map to business entities.

When Unit testing, I had to Mock<Database> and although creating a setup on ExecuteScalar, ExecuteNonQuery work fine, the ExecuteReader fail... because it's not virtual.

So i am not trying to derive from... just mocking. And I was wondering why it wasn't virtual.

Maybe would nice to have an abstract interface to represent a Database object.

--Robert
Feb 24, 2013 at 1:35 AM
Some options would be to use a different mocking framework, modify the Enterprise Library source to make the methods virtual or use an interface.

Or as the saying goes, "All problems in computer science can be solved by another level of indirection". You could create your own IDatabase interface and implementation to call the Enterprise Library Database class. So then your SqlManager would take an type of IDatabase instead of the abstract Database type.

I realize those aren't particularly pleasant/elegant options, though.

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to
Feb 24, 2013 at 2:04 AM
Hi Randy,

thanks for your advise.

I am aware of these techniques. I did create an internal virtual method to hide the call to allow me to test...

However, would simply make sense to make all those functions virtual to facilitate mocking. All other similar function are. Just my two cents!

I'll submit the request for that change, since i am not an 'active'member of the project.

Sent from my iPhone

On 2013-02-23, at 20:35, "randylevy" <notifications@codeplex.com> wrote:

From: randylevy

Some options would be to use a different mocking framework, modify the Enterprise Library source to make the methods virtual or use an interface.

Or as the saying goes, "All problems in computer science can be solved by another level of indirection". You could create your own IDatabase interface and implementation to call the Enterprise Library Database class. So then your SqlManager would take an type of IDatabase instead of the abstract Database type.

I realize those aren't particularly pleasant/elegant options, though.

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to
Feb 24, 2013 at 2:30 AM
I'll just say (and I know you know this :) ) that ideally you would have a data access layer and you would mock the data access layer so the internal implementation (ADO.NET, Enterprise Library, LINQ 2 SQL) wouldn't matter.

It's a bit late, but you could post your suggestion at UserVoice.

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to
Feb 24, 2013 at 3:15 AM
thanks again for your comment....

But I do have a Repositoy, that uses an IDataManager<T> that is implemented as an SqlManager, that uses a Database... i had reach a point where securing functionnality via Unit testing at SqlManager was necessary... And stumbled upon something that seemed liked an oversight, since almost all other functions were in fact virtual.

Cheers !
Sent from my iPhone

On 2013-02-23, at 21:30, "randylevy" <notifications@codeplex.com> wrote:

From: randylevy

I'll just say (and I know you know this :) ) that ideally you would have a data access layer and you would mock the data access layer so the internal implementation (ADO.NET, Enterprise Library, LINQ 2 SQL) wouldn't matter.

It's a bit late, but you could post your suggestion at UserVoice.

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to