define method that takes a method?

  • Thread starter Thread starter Michael Lang
  • Start date Start date
M

Michael Lang

Before offering architecture advice please read the short documentation for
this project at:
https://sourceforge.net/docman/display_doc.php?docid=18381&group_id=87262

if link does not work? try:
http://sourceforge.net/projects/genadonet
and go to "Docs" page, only 1 doc available...

I have a generic data access DLL that returns IDbDataAdapter for a given
data provider which is dynamically loaded at runtime. Unfortunately
IDbDataAdapter does not have the event 'RowUpdated' defined. however, every
provider has this method that takes basically the same arguements.

OleDbRowUpdatedEventArgs inherits from RowUpdateEventArgs
OleDbRowUpdatedEventHandler is defined as:
OleDbDataAdapter.RowUpdated(object sender, OleDbRowUpdatedEventArgs e)

SqlRowUpdatedEventArgs inherits from RowUpdatedEventArgs
SqlRowRowUpdatedEventHandler is defined as:
SqlDataAdapter.RowUpdated(object sender, SqlRowUpdatedEventArgs e);

same for Oracle, and Odbc providers...

I don't have a clue why IDbDataAdapter does not define RowUpdated?!

Anyway I have a "generic ADO.NET" project which you can see from link in my
signature. basically I provide a method that returns an IDbDataAdapter.
Actually, I have one for each overloaded constructor of IDbDataAdapter. i
have similar overloaded methods for all other IDb types (Connection,
DataParameter, Command).

The client can now develop database provider independant code. The provider
used is determined at run-time. Since IDbDataAdapter does not define any
events, I need to supply a way for users of the generic ADO dll to subscribe
to them. So far i created a method defined as...
==============================================
public interface IDbTemplate
{
...
void DataAdapterSubscribe(IDbDataAdapter da,
DataAdapterEvent evt, Delegate target);
...
}
==============================================

DataAdapterEvent is an enumeration of events supported by all providers
(Disposed, FillError, RowUpdated, RowUpdating)

'target' is supposed to accept a method pointer. Am I declaring it as the
wrong type?

here is how I implemented this for the Sql provider...
==============================================
public class DbSqlTemplate:DbTemplate
{
...
public void DataAdapterSubscribe(IDbDataAdapter source,
DataAdapterEvent evt, Delegate target)
{
SqlDataAdapter da = (SqlDataAdapter)source;
switch(evt)
{
case DataAdapterEvent.RowUpdated:
da.RowUpdated += new SqlRowUpdatedEventHandler(
(SqlRowUpdatedEventHandler)target);
break;
case DataAdapterEvent.RowUpdating:
da.RowUpdating += new SqlRowUpdatingEventHandler(
(SqlRowUpdatingEventHandler)target);
break;
case DataAdapterEvent.Disposed:
da.Disposed += new System.EventHandler(
(System.EventHandler)target);
break;
case DataAdapterEvent.FillError:
da.FillError += new FillErrorEventHandler(
(FillErrorEventHandler)target);
break;
} // end switch
} // end method
...
} //this code compiles with no errors or warnings...
==============================================

In the client I am trying to use this as follows:
==============================================
public void ReQuery(...)
{
...
_da = _context.DbContext.DbTemplate.DataAdapter(cmd);

if (!_context.DbContext.DbTemplate.SupportsMultiStepStatements)
{ //subscribe to the RowUpdated...
_context.DbContext.DbTemplate.DataAdapterSubscribe(_da,
GenDB.Data.DataAdapterEvent.RowUpdated,
this.OnRowUpdated); //compile error here...
// "method referenced without parenthesis"
}
...
}
protected void OnRowUpdated(object sender,
System.Data.Common.RowUpdatedEventArgs e)
{
if (e.StatementType == StatementType.Insert)
{
if (typeof(Int32) != typeof(System.Guid))
{ //numeric pk
IDbCommand cmdIden = GetIdentityCommand();
object newID = cmdIden.ExecuteScalar();
e.Row["ProductID"] = newID;
}
}
}
==============================================

--
Michael Lang, MCSD
See my .NET open source projects
http://sourceforge.net/projects/dbobjecter (code generator)
http://sourceforge.net/projects/genadonet ("generic" ADO.NET) - does not yet
include above described feature
 
Ah, yes. So basically create my own delegate. Sounds obvious now that you
mention it. Since there is a generic RowUpdateEventArgs, but no generic
RowUpdatedEventHandler I'll have to create a generic RowUpdatedEventHandler.
I'll post the results later.
 
Michael Lang said:
Having trouble.

defined in IDbTemplate...
void DataAdapterRowUpdated(IDbDataAdapter source,
RowUpdatedEventHandler target);

also defined
public delegate void RowUpdatedEventHandler(object sender,
System.Data.Common.RowUpdatedEventArgs e);

However, since SqlRowUpdatedEventHandler is not derived from
RowUpdatedEventHandler, I cannot cast instances of a RowUpdatedEventHandler
pased into my method into a SqlRowUpdatedEventHandler. They do have the
same arguements (or at least the sql one has arguements that derive from the
generic one). Isn't there a way to convert from the generic one to the
specific sql one?

That's what this method does.

private void raiseRowUpdating_sql(object o, SqlRowUpdatingEventArgs args )
{
RowUpdating(o,args);
}

I don't know of a more elegant way.

If not, I may just have to create a class that derives from IDbDataAdapter
and return that type instead of IDbDataAdapter. In my type I could define
all these generic events. I could subscribe to the underlying provider
events, and as a result raise my generic one to the client. That may be a
better architecture anyway. Let me know what you think...

Yeah, you can always wrapper the provider dataAdapter and pass through the
methods.
At a certian point it becomes easier to to that than to use the provider
types directly.

I do this with the connection.

David
 
I thought this method signature in the client was correct...

protected void OnRowUpdated(object sender,
System.Data.Common.RowUpdatedEventArgs e)
{
if (e.StatementType == StatementType.Insert)
{
IDbCommand cmdIden = GetIdentityCommand();
object newID = cmdIden.ExecuteScalar();
e.Row["ProductID"] = newID;
}
}

....since a SqlRowUpdatedEventArgs derives rom RowUpdatedEventArgs.
 
Having trouble.

defined in IDbTemplate...
void DataAdapterRowUpdated(IDbDataAdapter source,
RowUpdatedEventHandler target);

also defined
public delegate void RowUpdatedEventHandler(object sender,
System.Data.Common.RowUpdatedEventArgs e);

However, since SqlRowUpdatedEventHandler is not derived from
RowUpdatedEventHandler, I cannot cast instances of a RowUpdatedEventHandler
pased into my method into a SqlRowUpdatedEventHandler. They do have the
same arguements (or at least the sql one has arguements that derive from the
generic one). Isn't there a way to convert from the generic one to the
specific sql one?

If not, I may just have to create a class that derives from IDbDataAdapter
and return that type instead of IDbDataAdapter. In my type I could define
all these generic events. I could subscribe to the underlying provider
events, and as a result raise my generic one to the client. That may be a
better architecture anyway. Let me know what you think...
 
Back
Top