Should Derived Classes Provide Custom Exception?

J

jehugaleahsa

Hello:

Quick design question: should a derived class be expected to provide a
custom exception to the super class?

We caught ourselves writing the same code for executing SQL; something
like this:

using (IDbCommand command = _connection.CreateCommand())
{
command.CommandText = "";
using (IDataReader reader = command.ExecuteReader())
{
List<MyDO> results = new List<MyDO>();
while (reader.Read())
{
MyDo result = getResult(reader);
results.Add(result);
}
return results;
}
}

This is a lot of code to duplicate over and over in the application.
We created a simple class similar to the following to do most of this
for us:

public abstract class Command<TDataObject>
{
private readonly IDbConnection _connection;
protected Command(IDbConnection connection)
{
_connection = connection;
}
protected abstract string CommandText { get; }
protected abstract void AddParameters(<another helper class for
adding parameters>);
protected abstract TDataObject GetResult(IDataRecord record);

public IEnumerable<TDataObject> GetResults()
{
try
{
return getResults();
}
catch (DbException exception)
{ // throw custom exception
}
}

private IEnumerable<TDataObject> getResults()
{
using (IDbCommand command = _connection.CreateCommand())
{
command.CommandText = GetCommandText();
AddParameters(<our customer class for retrieving
parameters>);
using (IDataReader reader = command.ExecuteReader())
{
List<TDataObject> results = new List<TDataObject>();
while (reader.Read())
{
TDataObject result = GetResult(reader);
results.Add(result);
}
return results;
}
}
}
}

When a DbException occurs, we would like to wrap it in a custom
exception. The specific exception depends on the concrete class.
Should I add another method like this:

protected abstract Exception GetCustomException(DbException
exception);

This way the concrete class can wrap the given exception however is
appropriate. It seems a little weird to delegate exception handling to
the derived class. What are your thoughts?
 
J

jehugaleahsa

[...]
When a DbException occurs, we would like to wrap it in a custom
exception. The specific exception depends on the concrete class.
Should I add another method like this:
protected abstract Exception GetCustomException(DbException
exception);
This way the concrete class can wrap the given exception however is
appropriate. It seems a little weird to delegate exception handling to
the derived class. What are your thoughts?

Your example doesn't show why it is you want a custom exception at all.  
So, it's difficult to comment on appropriate ways to provide that custom  
exception.

My first reaction is that you should just let the DbException through.  
What value are you are you actually adding by using a custom exception?  I  
can hypothesize certain use cases, but none seem all that compelling to me.

Assuming you really want a custom exception, it seems to me that you could  
just make the custom exception generic as well, and then have your base  
class simply instantiate an appropriate instance if necessary.  Again, the  
question here would be: what value does the base class's  
"GetCustomException()" method add to the creation of the exception?

Anyway, the question seems vague.  Like I said, the most obvious answerto  
me is "don't even bother doing that".  :)

Pete

It's my understanding that exceptions are also part of a class'
interface. At leasts that's my opinion. In my situation here, I am
simply wrapping the DbException. That way, 20 miles up the call stack,
I don't have to handle DbExceptions - I can simply handle the custom
exception. Since I'm wrapping the exception, no information is being
lost; I can still retrieve it using InnerException.

This application has a strong separation between the layers. I don't
want the top layer to know that there even is a database. The top
layer should just mess with business objects and know no more. It
seems a violation of this to throw a DbException in its face. Custom
exceptions are pretty common for larger projects; just take a look
NHibernate, for instance.

I agree that I am splitting hairs here. One way or the other the same
exception gets to the top of the call stack. However, it seems more
appropriate to tell other developers that they just need to handle one
custom exception instead of multiple low-lever exceptions that they
may not even have DLL references for. I would be torqued if someone's
code required me to capture a generic exception just in case one-of-
many errors occurred.

I don't know; just my personal methodology. Just looking for some
worldy advice.
 
J

jehugaleahsa

[...]
When a DbException occurs, we would like to wrap it in a custom
exception. The specific exception depends on the concrete class.
Should I add another method like this:
protected abstract Exception GetCustomException(DbException
exception);
This way the concrete class can wrap the given exception however is
appropriate. It seems a little weird to delegate exception handling to
the derived class. What are your thoughts?

Your example doesn't show why it is you want a custom exception at all.  
So, it's difficult to comment on appropriate ways to provide that custom  
exception.

My first reaction is that you should just let the DbException through.  
What value are you are you actually adding by using a custom exception?  I  
can hypothesize certain use cases, but none seem all that compelling to me.

Assuming you really want a custom exception, it seems to me that you could  
just make the custom exception generic as well, and then have your base  
class simply instantiate an appropriate instance if necessary.  Again, the  
question here would be: what value does the base class's  
"GetCustomException()" method add to the creation of the exception?

Anyway, the question seems vague.  Like I said, the most obvious answerto  
me is "don't even bother doing that".  :)

Pete

It's my understanding that exceptions are also part of a class'
interface. At leasts that's my opinion. In my situation here, I am
simply wrapping the DbException. That way, 20 miles up the call stack,
I don't have to handle DbExceptions - I can simply handle the custom
exception. Since I'm wrapping the exception, no information is being
lost; I can still retrieve it using InnerException.

This application has a strong separation between the layers. I don't
want the top layer to know that there even is a database. The top
layer should just mess with business objects and know no more. It
seems a violation of this to throw a DbException in its face. Custom
exceptions are pretty common for larger projects; just take a look
NHibernate, for instance.

I agree that I am splitting hairs here. One way or the other the same
exception gets to the top of the call stack. However, it seems more
appropriate to tell other developers that they just need to handle one
custom exception instead of multiple low-lever exceptions that they
may not even have DLL references for. I would be torqued if someone's
code required me to capture a generic exception just in case one-of-
many errors occurred.

I don't know; just my personal methodology. Just looking for some
worldy advice.
 
P

Pavel Minaev

It's my understanding that exceptions are also part of a class'
interface. At leasts that's my opinion. In my situation here, I am
simply wrapping the DbException. That way, 20 miles up the call stack,
I don't have to handle DbExceptions - I can simply handle the custom
exception. Since I'm wrapping the exception, no information is being
lost; I can still retrieve it using InnerException.

This application has a strong separation between the layers. I don't
want the top layer to know that there even is a database. The top
layer should just mess with business objects and know no more. It
seems a violation of this to throw a DbException in its face.

That's all well and good, but why would you need a distinct exception
type for every TDataObject? It would seem that something simple and
generic, like DataObjectLoadException would do just fine here.
 
P

Pavel Minaev

It's my understanding that exceptions are also part of a class'
interface. At leasts that's my opinion. In my situation here, I am
simply wrapping the DbException. That way, 20 miles up the call stack,
I don't have to handle DbExceptions - I can simply handle the custom
exception. Since I'm wrapping the exception, no information is being
lost; I can still retrieve it using InnerException.

This application has a strong separation between the layers. I don't
want the top layer to know that there even is a database. The top
layer should just mess with business objects and know no more. It
seems a violation of this to throw a DbException in its face.

That's all well and good, but why would you need a distinct exception
type for every TDataObject? It would seem that something simple and
generic, like DataObjectLoadException would do just fine here.
 
P

Paul

The question here is are you writing a framework for others to use or are
you writing an application?

If you are writing a framework then I would say possibly(timescales etc).
Otherwise I would say no, unless your requirements state it is needed.

I do something similar to yourself but do not use custom exceptions. I
created a DataProvider As I call it which is used by the DAL. The provider
has no knowledge of ModelTypes and passes back an IDataReader, it also
inherits Idisposable.

It identifies numerous methods but exposes executereader, executescalar,
executenonquery etc.

ExecuteNonQuery passes back a custom object that identifies created id's on
insert, return values etc. This can then be passed back to the BLL via the
DAL for a decision on what happens next.


BLL - Decision Maker

DAL - Translates objects to SQL (roughly speaking)

Data Provider - Translates Data Interface objects to specific database type
providers (SQL, ORACLE, MY SQL) requires some play around creating
parameters of certain types however.

Does not really answer your question but maybe it will help.
 
P

Paul

The question here is are you writing a framework for others to use or are
you writing an application?

If you are writing a framework then I would say possibly(timescales etc).
Otherwise I would say no, unless your requirements state it is needed.

I do something similar to yourself but do not use custom exceptions. I
created a DataProvider As I call it which is used by the DAL. The provider
has no knowledge of ModelTypes and passes back an IDataReader, it also
inherits Idisposable.

It identifies numerous methods but exposes executereader, executescalar,
executenonquery etc.

ExecuteNonQuery passes back a custom object that identifies created id's on
insert, return values etc. This can then be passed back to the BLL via the
DAL for a decision on what happens next.


BLL - Decision Maker

DAL - Translates objects to SQL (roughly speaking)

Data Provider - Translates Data Interface objects to specific database type
providers (SQL, ORACLE, MY SQL) requires some play around creating
parameters of certain types however.

Does not really answer your question but maybe it will help.
 
S

sloan

I would read Krzysztof's article:
http://blogs.msdn.com/kcwalina/archive/2005/03/16/396787.aspx


The "exception is a part of a class' definition" seems to be more of a java
thing IIRC.


You can write
try/finally blocks
and just omit the catch.

Letting DbException bubble up to the BAL would make more sense to me.
Then if you need to catch it there, and then wrap it up in custom exception,
that would be the place to do it.
This would ONLY be so the end-user doesn't see some kind of "FK violation"
(or similar) exceptions.

...............
 
S

sloan

I would read Krzysztof's article:
http://blogs.msdn.com/kcwalina/archive/2005/03/16/396787.aspx


The "exception is a part of a class' definition" seems to be more of a java
thing IIRC.


You can write
try/finally blocks
and just omit the catch.

Letting DbException bubble up to the BAL would make more sense to me.
Then if you need to catch it there, and then wrap it up in custom exception,
that would be the place to do it.
This would ONLY be so the end-user doesn't see some kind of "FK violation"
(or similar) exceptions.

...............
 
J

jehugaleahsa

That's all well and good, but why would you need a distinct exception
type for every TDataObject? It would seem that something simple and
generic, like DataObjectLoadException would do just fine here.

There are multiple instances in my code where I like to display the
exact object that caused an error. For instance, when I am inserting
or updating a record, I like to display the contents of that record to
help the user (or the developers) to identify the cause of the
problem. I go about doing this by passing the data object along with
the exception. Later, the exception handling mechanism will look at
the data object and create a detailed error message. Does that make
sense?

I only do this when necessary. In this case, I have Commands that are
trying to, say, insert a record. I want to make sure that the record
is included in the exception. If I let the exception get outside the
bounds of the class, the record disappears.
 
J

jehugaleahsa

That's all well and good, but why would you need a distinct exception
type for every TDataObject? It would seem that something simple and
generic, like DataObjectLoadException would do just fine here.

There are multiple instances in my code where I like to display the
exact object that caused an error. For instance, when I am inserting
or updating a record, I like to display the contents of that record to
help the user (or the developers) to identify the cause of the
problem. I go about doing this by passing the data object along with
the exception. Later, the exception handling mechanism will look at
the data object and create a detailed error message. Does that make
sense?

I only do this when necessary. In this case, I have Commands that are
trying to, say, insert a record. I want to make sure that the record
is included in the exception. If I let the exception get outside the
bounds of the class, the record disappears.
 
J

jehugaleahsa

Well, as always, everyone is entitled to their opinion.  :)  And depending  
on what you mean by "a class's interface", perhaps I'd agree.  But, by my  
usual interpretation of "a class's interface", I can't.  Assuming by  
"interface" you mean that a class will have class-specific exceptions,  
that's not my approach, nor is it the approach taken by all of .NET.

What does often happen is that exception types will be declared for  
specific groups of classes, usually within a given namespace for use  
within that namespace.  But even there, that generally happens only when  
the specific exception _adds_ something to the error reporting.  A  
namespace-specific exception isn't created just to avoid throwing  
exceptions from some other namespace.

Oh, I totally agree. Only a mad man would create an exception for
every class in their system. That's just too much work. However, I do
have some essential classes that should be included as parts of an
exception handling. These are usually classes that are inserted in
batches. It is hard to identify the exact record that caused an error
otherwise. I will usually pass the record ID to the exception.
I don't object to the idea of a custom exception.  I simply object to a 
custom exception being declared simply to avoid using some other exception.

Agreed again, mostly. You should use classes like ArgumentException
when you are handed a bad argument. I only wrap the DbException
because I don't want the rest of the system to know about a database-
specific class... and because I want to pass additional information.
That said, if you have some sort of way to generalize the kinds of errors 
that might occur in one layer, so that when exposed to another layer, that  
other layer need not bother with anything other than knowing of that  
generalized error, perhaps that's an appropriate strategy.  But even  
there, it's not clear to me that you need to declare class-specific, or  
even namespace-specific exceptions.  There are plenty of pre-existing  
exceptions within .NET that do a good job of describing the general  
failure that may have occurred due to some more-specific problem.

Yes. There are a lot. The question is: custom exception per layer, per
library, per application? I don't know from experience. An equally
valid question is whether I should be placing more detailed
information in the exception message itself. I could avoid passing
objects in exceptions that way. I could reduce my exceptions down to,
say, one custom exception? That is something I will have to think
about. Less work always sounds inviting.
For example, perhaps a database error is reflective of a more general  
invalid state within the class, in which case an InvalidOperationException  
might be appropriate.  Or, maybe the database is one specific type of i/o  
the class performs, but all errors for that class of operations can be  
generalized as i/o errors.  In which case, IOException might be  
appropriate.  Or, perhaps your code is organized in a way that you can  
distinguish between database errors due to invalid arguments, and errors  
due to i/o problems.  In which case, you might select either  
ArgumentException or IOException accordingly.

Finally, maybe you've got a genuine situation that calls for a custom  
exception.  But if so, why does that exception have to be specific to each  
concrete derived class of the abstract, generic base class?  If your goal  
is simply to abstract the lower-level errors, so that the higher-level  
layers don't have to concern themselves with implementation details, it  
seems like a single exception specific to the abstract class, or even just  
to its namespace for that matter, would suffice.

Right. Per-class exceptions are a no go.
These are not just rhetorical questions.  They are directly pertinent to  
your original post, and answers to them are required in order to provide  
the most useful advice.

You've given me plenty to think about and I may have come upon an
answer.
What do you mean by "generic exception"?  Do you mean using  
"System.Exception" as the type in the "catch" clause?  If so, is there  
actually something specific wrong with that?

Yes. I do mean a catch all. I have found that it is always possible to
avoiding catching Exception. However, I used them some times as a fail-
safe. They are good for stopping your application from bombing out
entirely if something unexpected does go wrong. But I believe their
use should limited to a very small number of situations.
I catch specific exceptions when knowing the difference matters to my  
code, and my exception handling in particular.  For example, my network 
i/o code knows that IOExceptions happen as part of normal operation, but  
other exceptions don't.  So I'll catch IOExceptions specifically, and  
others more generally (i.e. with System.Exception).

Again, I'm not going to say that there's no use in using a custom  
exception, or generalizing in some other way.  But one shouldn't go about  
it simply due to dogma.  There should be some practical, explainable  
benefit.

Agreed. Rigorous compliant to such a rule when your app is going to go
down really doesn't do you any good. Some times a simple, "Oops!" is
really all anyone ever needs.
I'm not the oldest, wisest, most worldly person around.  But I do have a  
few decades of programming under my belt, and I've found that one of the  
best rules is "keep it simple" (this turns out to apply in a wide variety 
of other pursuits I engage in as well :) ).

A broad framework like .NET is an interesting paradox; it enables  
convenient access to a wide variety of technologies, often while allowing 
the programmer to use those technologies with a relatively small amount of  
custom code.  And yet, there's an aspect of the environment that tends to  
encourage complexity for some reason.  It's important to remember that  
just because you _can_ do something, that doesn't mean you should.  :)

In this context, the implication is that you should avoid adding  
complexity unless you have some qualified, quantifiable gain.  It's  
entirely possible that that gain is in fact a _reduction_ in complexity in  
a different area of the code.  In which case, that may well be a good  
trade-off.  But it's important in adding complexity in one place, so that  
you can reduce complexity elsewhere, that you only add _just enough_  
complexity to accomplish the goal.

Would you say the same things for an application that is expected to
receive maintenance for the next decade? As I've told you before, my
code is rather large and so I get single-minded rather often. I
usually overcompensate. It is something of an art to stop creating
more abstractions. I miss the mark quite often.
Don't add a new exception if there's an already-existing exception that  
will suffice.  Don't add a class-specific exception if a single  
namespace-specific exception will suffice.  Don't add a per-derived-class  
exception if a single base-class-specific exception will suffice.  And if  
you do wind up with a per-derived-class exception, don't require each  
derived class to declare their own exceptions, when a single generic  
exception declared in the base class, using the type parameter for your  
generic class, will suffice.

Pete

Here is what I think I will do. I think I will trash some of my
exceptions. Instead, I think I will create one custom exception for my
database layer. I will simply put more effort into making my error
messages meaningful. The subclasses should have the responsibility and
the know-how to create meaningful messages. Less exceptions means less
work and less work means less mistakes. I will have to check the
exception handling code to see what it does with the passed data
objects. I have a feeling I will find that it simply creates an error
message. 1-2-3 make the message of the exception the error message.
Eliminate the error handling code and eliminate a bunch of exception
classes. I like it.
 
J

jehugaleahsa

Well, as always, everyone is entitled to their opinion.  :)  And depending  
on what you mean by "a class's interface", perhaps I'd agree.  But, by my  
usual interpretation of "a class's interface", I can't.  Assuming by  
"interface" you mean that a class will have class-specific exceptions,  
that's not my approach, nor is it the approach taken by all of .NET.

What does often happen is that exception types will be declared for  
specific groups of classes, usually within a given namespace for use  
within that namespace.  But even there, that generally happens only when  
the specific exception _adds_ something to the error reporting.  A  
namespace-specific exception isn't created just to avoid throwing  
exceptions from some other namespace.

Oh, I totally agree. Only a mad man would create an exception for
every class in their system. That's just too much work. However, I do
have some essential classes that should be included as parts of an
exception handling. These are usually classes that are inserted in
batches. It is hard to identify the exact record that caused an error
otherwise. I will usually pass the record ID to the exception.
I don't object to the idea of a custom exception.  I simply object to a 
custom exception being declared simply to avoid using some other exception.

Agreed again, mostly. You should use classes like ArgumentException
when you are handed a bad argument. I only wrap the DbException
because I don't want the rest of the system to know about a database-
specific class... and because I want to pass additional information.
That said, if you have some sort of way to generalize the kinds of errors 
that might occur in one layer, so that when exposed to another layer, that  
other layer need not bother with anything other than knowing of that  
generalized error, perhaps that's an appropriate strategy.  But even  
there, it's not clear to me that you need to declare class-specific, or  
even namespace-specific exceptions.  There are plenty of pre-existing  
exceptions within .NET that do a good job of describing the general  
failure that may have occurred due to some more-specific problem.

Yes. There are a lot. The question is: custom exception per layer, per
library, per application? I don't know from experience. An equally
valid question is whether I should be placing more detailed
information in the exception message itself. I could avoid passing
objects in exceptions that way. I could reduce my exceptions down to,
say, one custom exception? That is something I will have to think
about. Less work always sounds inviting.
For example, perhaps a database error is reflective of a more general  
invalid state within the class, in which case an InvalidOperationException  
might be appropriate.  Or, maybe the database is one specific type of i/o  
the class performs, but all errors for that class of operations can be  
generalized as i/o errors.  In which case, IOException might be  
appropriate.  Or, perhaps your code is organized in a way that you can  
distinguish between database errors due to invalid arguments, and errors  
due to i/o problems.  In which case, you might select either  
ArgumentException or IOException accordingly.

Finally, maybe you've got a genuine situation that calls for a custom  
exception.  But if so, why does that exception have to be specific to each  
concrete derived class of the abstract, generic base class?  If your goal  
is simply to abstract the lower-level errors, so that the higher-level  
layers don't have to concern themselves with implementation details, it  
seems like a single exception specific to the abstract class, or even just  
to its namespace for that matter, would suffice.

Right. Per-class exceptions are a no go.
These are not just rhetorical questions.  They are directly pertinent to  
your original post, and answers to them are required in order to provide  
the most useful advice.

You've given me plenty to think about and I may have come upon an
answer.
What do you mean by "generic exception"?  Do you mean using  
"System.Exception" as the type in the "catch" clause?  If so, is there  
actually something specific wrong with that?

Yes. I do mean a catch all. I have found that it is always possible to
avoiding catching Exception. However, I used them some times as a fail-
safe. They are good for stopping your application from bombing out
entirely if something unexpected does go wrong. But I believe their
use should limited to a very small number of situations.
I catch specific exceptions when knowing the difference matters to my  
code, and my exception handling in particular.  For example, my network 
i/o code knows that IOExceptions happen as part of normal operation, but  
other exceptions don't.  So I'll catch IOExceptions specifically, and  
others more generally (i.e. with System.Exception).

Again, I'm not going to say that there's no use in using a custom  
exception, or generalizing in some other way.  But one shouldn't go about  
it simply due to dogma.  There should be some practical, explainable  
benefit.

Agreed. Rigorous compliant to such a rule when your app is going to go
down really doesn't do you any good. Some times a simple, "Oops!" is
really all anyone ever needs.
I'm not the oldest, wisest, most worldly person around.  But I do have a  
few decades of programming under my belt, and I've found that one of the  
best rules is "keep it simple" (this turns out to apply in a wide variety 
of other pursuits I engage in as well :) ).

A broad framework like .NET is an interesting paradox; it enables  
convenient access to a wide variety of technologies, often while allowing 
the programmer to use those technologies with a relatively small amount of  
custom code.  And yet, there's an aspect of the environment that tends to  
encourage complexity for some reason.  It's important to remember that  
just because you _can_ do something, that doesn't mean you should.  :)

In this context, the implication is that you should avoid adding  
complexity unless you have some qualified, quantifiable gain.  It's  
entirely possible that that gain is in fact a _reduction_ in complexity in  
a different area of the code.  In which case, that may well be a good  
trade-off.  But it's important in adding complexity in one place, so that  
you can reduce complexity elsewhere, that you only add _just enough_  
complexity to accomplish the goal.

Would you say the same things for an application that is expected to
receive maintenance for the next decade? As I've told you before, my
code is rather large and so I get single-minded rather often. I
usually overcompensate. It is something of an art to stop creating
more abstractions. I miss the mark quite often.
Don't add a new exception if there's an already-existing exception that  
will suffice.  Don't add a class-specific exception if a single  
namespace-specific exception will suffice.  Don't add a per-derived-class  
exception if a single base-class-specific exception will suffice.  And if  
you do wind up with a per-derived-class exception, don't require each  
derived class to declare their own exceptions, when a single generic  
exception declared in the base class, using the type parameter for your  
generic class, will suffice.

Pete

Here is what I think I will do. I think I will trash some of my
exceptions. Instead, I think I will create one custom exception for my
database layer. I will simply put more effort into making my error
messages meaningful. The subclasses should have the responsibility and
the know-how to create meaningful messages. Less exceptions means less
work and less work means less mistakes. I will have to check the
exception handling code to see what it does with the passed data
objects. I have a feeling I will find that it simply creates an error
message. 1-2-3 make the message of the exception the error message.
Eliminate the error handling code and eliminate a bunch of exception
classes. I like it.
 
J

jehugaleahsa

The question here is are you writing a framework for others to use or are
you writing an application?

It is both, sorta. No one outside of my company will use this code.
However, the same set of code is shared across multiple tiers of the
application. There are server-side application and client-side
applications. Other developers use my code to implement them. An in-
house framework, I guess.
If you are writing a framework then I would say possibly(timescales etc).
Otherwise I would say no, unless your requirements state it is needed.

I do something similar to yourself but do not use custom exceptions. I
created a DataProvider As I call it which is used by the DAL. The provider
has no knowledge of ModelTypes and passes back an IDataReader, it also
inherits Idisposable.

It identifies numerous methods but exposes executereader, executescalar,
executenonquery etc.

ExecuteNonQuery passes back a custom object that identifies created id's on
insert, return values etc. This can then be passed back to the BLL via the
DAL for a decision on what happens next.

This sounds similar to my exception handling code. Usually, there
isn't much in the way of decision making. Either the exception is
handled or it keeps moving up the stack. It is mostly for diagnostics.
BLL - Decision Maker

DAL - Translates objects to SQL (roughly speaking)

Data Provider - Translates Data Interface objects to specific database type
providers (SQL, ORACLE, MY SQL) requires some play around creating
parameters of certain types however.

I've played the ORM game before. How do you use System.DbType to refer
to an Oracle cursor or BLOB? :)
Does not really answer your question but maybe it will help.

It is just one more voice adding to my growing feeling that I may be
trying too hard.
 
J

jehugaleahsa

The question here is are you writing a framework for others to use or are
you writing an application?

It is both, sorta. No one outside of my company will use this code.
However, the same set of code is shared across multiple tiers of the
application. There are server-side application and client-side
applications. Other developers use my code to implement them. An in-
house framework, I guess.
If you are writing a framework then I would say possibly(timescales etc).
Otherwise I would say no, unless your requirements state it is needed.

I do something similar to yourself but do not use custom exceptions. I
created a DataProvider As I call it which is used by the DAL. The provider
has no knowledge of ModelTypes and passes back an IDataReader, it also
inherits Idisposable.

It identifies numerous methods but exposes executereader, executescalar,
executenonquery etc.

ExecuteNonQuery passes back a custom object that identifies created id's on
insert, return values etc. This can then be passed back to the BLL via the
DAL for a decision on what happens next.

This sounds similar to my exception handling code. Usually, there
isn't much in the way of decision making. Either the exception is
handled or it keeps moving up the stack. It is mostly for diagnostics.
BLL - Decision Maker

DAL - Translates objects to SQL (roughly speaking)

Data Provider - Translates Data Interface objects to specific database type
providers (SQL, ORACLE, MY SQL) requires some play around creating
parameters of certain types however.

I've played the ORM game before. How do you use System.DbType to refer
to an Oracle cursor or BLOB? :)
Does not really answer your question but maybe it will help.

It is just one more voice adding to my growing feeling that I may be
trying too hard.
 
J

jehugaleahsa

I would read Krzysztof's article:http://blogs.msdn.com/kcwalina/archive/2005/03/16/396787.aspx

The "exception is a part of a class' definition" seems to be more of a java
thing IIRC.

You can write
try/finally blocks
and just omit the catch.

Letting DbException bubble up to the BAL would make more sense to me.
Then if you need to catch it there, and then wrap it up in custom exception,
that would be the place to do it.
This would ONLY be so the end-user doesn't see some kind of "FK violation"
(or similar) exceptions.

..............
















- Show quoted text -

Oh, but those people who write big books say that you should never let
a database exception escape the data layer. :) I agree. On some of my
smaller applications, I am happy to let just about any old exception
through my net. On the application I am working on now, though, I have
to be mindful, but not dogmatic (as Peter said).
 
J

jehugaleahsa

I would read Krzysztof's article:http://blogs.msdn.com/kcwalina/archive/2005/03/16/396787.aspx

The "exception is a part of a class' definition" seems to be more of a java
thing IIRC.

You can write
try/finally blocks
and just omit the catch.

Letting DbException bubble up to the BAL would make more sense to me.
Then if you need to catch it there, and then wrap it up in custom exception,
that would be the place to do it.
This would ONLY be so the end-user doesn't see some kind of "FK violation"
(or similar) exceptions.

..............
















- Show quoted text -

Oh, but those people who write big books say that you should never let
a database exception escape the data layer. :) I agree. On some of my
smaller applications, I am happy to let just about any old exception
through my net. On the application I am working on now, though, I have
to be mindful, but not dogmatic (as Peter said).
 
P

Paul

If you don't need to provide custom exception they don't you are adding a
step of complexity, and more complexity genrally ends up with more time and
more chance of failure.
I've played the ORM game before. How do you use System.DbType to refer
to an Oracle cursor or BLOB? :)

Ahhh very good question.

First you need to understand that for 75% System.DbType will work. But
remember I said I created a Provider and a DAL.

The Provider does no ORM, but the base class provides methods for creating
parameters, these can then be overidden in the implementing classes were
needed.

Lets look into the archives as I no longer use
Oracle.................Here...

e.g.
public abstract IDbDataParameter CreateParameter ( string parameterName,
object value, DbType dbType, ParameterDirection direction );

public abstract IDbDataParameter CreateParameterBlob ( string parameterName,
object value, int? size, ParameterDirection direction );

public abstract IDbDataParameter CreateParameterClob ( string parameterName,
object value, ParameterDirection direction );



my sql server implemetations go like this



public override IDbDataParameter CreateParameter ( string parameterName,
object value, DbType dbType, int? size, ParameterDirection direction )

{

SqlParameter parameter = new SqlParameter ( );

parameter.ParameterName = parameterName;

parameter.DbType = dbType;

parameter.Value = value;

if ( size != null )

parameter.Size = ( int )size;

parameter.Direction = direction;

return parameter;

}



public override IDbDataParameter CreateParameterClob ( string parameterName,
object value, ParameterDirection direction )

{

SqlParameter parameter = new SqlParameter ( );

parameter.ParameterName = parameterName;

parameter.SqlDbType = SqlDbType.Text;

parameter.Value = value;

parameter.Direction = direction;

return parameter;

}

public override IDbDataParameter CreateParameterBlob ( string parameterName,
object value, int? size, ParameterDirection direction )

{

SqlParameter parameter = new SqlParameter ( );

parameter.ParameterName = parameterName;

parameter.SqlDbType = SqlDbType.VarBinary;

parameter.Value = value;

if ( size != null )

parameter.Size = ( int )size;

parameter.Direction = direction;

return parameter;

}



And the Oracle like this



public override IDbDataParameter CreateParameter ( string parameterName,
object value, DbType dbType, int? size, ParameterDirection direction )

{

try

{

OracleParameter parameter = new OracleParameter ( );

parameter.ParameterName = ":" + parameterName;

if ( value is DBNull )

parameter.IsNullable = true;

switch ( dbType )

{

case DbType.Boolean:

parameter.OracleDbType = OracleDbType.Char;

parameter.Size = 1;

parameter.Value = BaseDBProvider.OraBit ( ( bool )value );


break;

default:

parameter.DbType = dbType;

parameter.Value = value;

break;

}

if ( size != null )

parameter.Size = ( int )size;

parameter.Direction = direction;

return parameter;

}

catch( Exception ex )

{

throw new Exception ( "Failed Creating a parameter. See inner exception for
details", ex );

}

}

public override IDbDataParameter CreateParameterClob ( string parameterName,
object value, ParameterDirection direction )

{

OracleParameter parameter = new OracleParameter ( );

parameter.ParameterName = parameterName;

parameter.OracleDbType = OracleDbType.Clob;

parameter.Value = value;

parameter.Direction = direction;

return parameter;

}

public override IDbDataParameter CreateParameterBlob ( string parameterName,
object value, int? size, ParameterDirection direction )

{

OracleParameter parameter = new OracleParameter ( );

parameter.ParameterName = parameterName;

parameter.OracleDbType = OracleDbType.Blob;

parameter.Value = value;

if ( size != null )

parameter.Size = ( int )size;

parameter.Direction = direction;

return parameter;

}



It can also be handled like I handled the Boolean in the Oracle
CreateParameter.
It is just one more voice adding to my growing feeling that I may be
trying too hard.


LOL. Well stick with it brother there is light at the end of the tunnel
 
P

Paul

If you don't need to provide custom exception they don't you are adding a
step of complexity, and more complexity genrally ends up with more time and
more chance of failure.
I've played the ORM game before. How do you use System.DbType to refer
to an Oracle cursor or BLOB? :)

Ahhh very good question.

First you need to understand that for 75% System.DbType will work. But
remember I said I created a Provider and a DAL.

The Provider does no ORM, but the base class provides methods for creating
parameters, these can then be overidden in the implementing classes were
needed.

Lets look into the archives as I no longer use
Oracle.................Here...

e.g.
public abstract IDbDataParameter CreateParameter ( string parameterName,
object value, DbType dbType, ParameterDirection direction );

public abstract IDbDataParameter CreateParameterBlob ( string parameterName,
object value, int? size, ParameterDirection direction );

public abstract IDbDataParameter CreateParameterClob ( string parameterName,
object value, ParameterDirection direction );



my sql server implemetations go like this



public override IDbDataParameter CreateParameter ( string parameterName,
object value, DbType dbType, int? size, ParameterDirection direction )

{

SqlParameter parameter = new SqlParameter ( );

parameter.ParameterName = parameterName;

parameter.DbType = dbType;

parameter.Value = value;

if ( size != null )

parameter.Size = ( int )size;

parameter.Direction = direction;

return parameter;

}



public override IDbDataParameter CreateParameterClob ( string parameterName,
object value, ParameterDirection direction )

{

SqlParameter parameter = new SqlParameter ( );

parameter.ParameterName = parameterName;

parameter.SqlDbType = SqlDbType.Text;

parameter.Value = value;

parameter.Direction = direction;

return parameter;

}

public override IDbDataParameter CreateParameterBlob ( string parameterName,
object value, int? size, ParameterDirection direction )

{

SqlParameter parameter = new SqlParameter ( );

parameter.ParameterName = parameterName;

parameter.SqlDbType = SqlDbType.VarBinary;

parameter.Value = value;

if ( size != null )

parameter.Size = ( int )size;

parameter.Direction = direction;

return parameter;

}



And the Oracle like this



public override IDbDataParameter CreateParameter ( string parameterName,
object value, DbType dbType, int? size, ParameterDirection direction )

{

try

{

OracleParameter parameter = new OracleParameter ( );

parameter.ParameterName = ":" + parameterName;

if ( value is DBNull )

parameter.IsNullable = true;

switch ( dbType )

{

case DbType.Boolean:

parameter.OracleDbType = OracleDbType.Char;

parameter.Size = 1;

parameter.Value = BaseDBProvider.OraBit ( ( bool )value );


break;

default:

parameter.DbType = dbType;

parameter.Value = value;

break;

}

if ( size != null )

parameter.Size = ( int )size;

parameter.Direction = direction;

return parameter;

}

catch( Exception ex )

{

throw new Exception ( "Failed Creating a parameter. See inner exception for
details", ex );

}

}

public override IDbDataParameter CreateParameterClob ( string parameterName,
object value, ParameterDirection direction )

{

OracleParameter parameter = new OracleParameter ( );

parameter.ParameterName = parameterName;

parameter.OracleDbType = OracleDbType.Clob;

parameter.Value = value;

parameter.Direction = direction;

return parameter;

}

public override IDbDataParameter CreateParameterBlob ( string parameterName,
object value, int? size, ParameterDirection direction )

{

OracleParameter parameter = new OracleParameter ( );

parameter.ParameterName = parameterName;

parameter.OracleDbType = OracleDbType.Blob;

parameter.Value = value;

if ( size != null )

parameter.Size = ( int )size;

parameter.Direction = direction;

return parameter;

}



It can also be handled like I handled the Boolean in the Oracle
CreateParameter.
It is just one more voice adding to my growing feeling that I may be
trying too hard.


LOL. Well stick with it brother there is light at the end of the tunnel
 
P

Paul

Oh and back on topic.

The reason I say only provide custom exceptions if you are using a framework
is because 99% of the time the only person viewing an exception will be the
developer and providing developers with erros is a good thing.

99% of time an exception/failure to do something should be handled by BLL
and not present the error to the user. So the user just understands that his
Update to the database failed, all he wants to know then is that it failed
and whether he can try again. Not that his error occured because of a
deadlock in the DB......, so providing a custom error to suit users
generalizes the error which is then no good for the developer.

I tend to find as a developer the Stack Trace is more important for
debugging than anything even the actual error message sometimes. The problem
is incorrect use of custom exception can hide this stack trace and correct
use is very very time consuming.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top