.NET OOP design question - DataLayer

Hi all,

I'm trying to build an articles system in .NET, with different article types. The most logical thing is to create a base class for the basic article type (or an interface), and then to create all the article types as derived class - this is how I figure it should be done with .NET.

My problem is how to create the relation between the data store and article type defined in code:

Assume I have a DB table tbl_Articles and within it I store all the basic article data, and also a field (assume int) which defines the article type (article_type). How do I write code in my BLL which will "know" what article type this ID represents? Can I run through all derived classes of my ArticleBase class (or IArticle interface) - assuming same namespace, and taking into account more than one level inheritance - and compare the value of that int in each data row against a static variable in those classes, holding the unique integer ID of the article type? is there a better approach, whithout hardcoding the values in the BLL/DAL loading code (to allow for easier extension)?

I'm using C#, VS2005, .NET 2.0.

Stilgar.
LVL 14
_Stilgar_Asked:
Who is Participating?

Improve company productivity with a Business Account.Sign Up

x
 
Alexandre SimõesConnect With a Mentor Manager / Technology SpecialistCommented:
I'm attaching 3 files, please rename their extensions to .cs
Add the files to a Console Project and run the attached snippet.

This will discover all implementations of the IMyInterface on all files found on the exe folder.
With the resulting list of implementations it instatiates each type and call the StartIt() method.


List<Type> types = DiscoverInterface.Discover.DiscoverMyInterface();
foreach (Type t in types)
{
	DiscoverInterface.Discover.StartIt(t);
}
Console.ReadLine();

Open in new window

Discover.txt
IMyInterface.txt
MyImplementation.txt
0
 
daveamourCommented:
I would look into using an enumeration.
0
 
_Stilgar_Author Commented:
If I understand what you mean correctly, an enumeration would be hardcoding all the possible values in one place (somewhere in the BLL/DAL), so every time I add a new class (article type) I will be required to add it to the enumeration as well - exactly what I'm trying to avoid.
0
Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

 
Alexandre SimõesManager / Technology SpecialistCommented:
At the end you said it all: "without hard-coding the values in the BLL/DAL loading code"

If you want it to be extendable without having to recompile your code you'll have to get the values from the database.

My suggestion is the following:

Create a base class (not just an interface) that have all the Articles table columns plus a ArticleType readonly property that returns an ArticleType object.

On this property you'll put code to retrieve the ArticleType object based on the ArticleTypeID that you have from the Articles table. Remember to store this value on a provate variable so you only need to get this once per object.

Sure this is expensive when it comes to performance, but it depends on the amount of records and how often you need to get the ArticleType object.


Too much data... Too slow...
If we're dealing with a large amount of records here I suggest you make a stored procedure or a custom query (depending on your database engine) to retrieve all the articles data already with the ArticleType field(s) you need.

Architectural thoughts...
People (developers) often tend to create their Business Layers as an image of the Data Layer... one class per table... but this isn't always practical.
Our business rules do not need to have a clean hierarchical/relational representation that often leads to an expensive number connections to the database.


Hope this helps,
Cheers!

Alex
0
 
_Stilgar_Author Commented:
Thanks for your response.

Having a cenralized location where all the possible article types are defined, is exactly what I'm trying to avoid. The idea here is not to allow for creating new types without re-compiling, because that will never be the case (new types will always require new correspinding classes), but to create a mechanim to automatically detect and support new types.

My idea was to somehow utilize reflection to get a list of all classes in a namespace, and then to iterate through all of them and check a common static variable/function in each, which will hold the article type. Not sure if it's possible, and whether it's considered safe and "on the right track", hence my question.

What do you think? do you have a better idea?
0
 
Alexandre SimõesManager / Technology SpecialistCommented:
"but to create a mechanim to automatically detect and support new types."

Inherit from that base class I mentioned. You have a ArticleTypes table right? That base class will only have a read only property, public, that retrieves the ArticleType and another one also readonly but abstract that will hold the ArticleTypeID.

When you inherit from this class you'll be forced to fill the get of the ArticleTypeID property. Retrieve the ID corresponding to the type you're implementing.

You then can enumerate all the types and "ask" for the ArticleTypeID or the ArticleType object itself.


Note:
We're pretty much hardcoding here... To add a new type without recompiling you need to implement some sort of plugin architecture.
You may want to add a new assembly to your already deployed application and make it descoverable.
The application must iterate through all the available assemblies, open them and search for implementations of our base class.


Tell me more about what you're trying to achieve.

Cheers,
Alex
0
 
Anurag ThakurTechnical ManagerCommented:
the author mentioned the word hard coding for enums in the code but i think its the best way out because if a new article type is added then any way the code has to be written to hanlde it accordingly and in case the article types can be added without writing coding logic then build a plug and play component in which you can add a new enum value and update the reference without affecting the complete system (but still the article type has to be used in coding logic else its of no use)
0
 
_Stilgar_Author Commented:
I have no choice but to hardcode, but question is what and where. What I want to do is make each article type it's own class (obviously), and that class will hold the unique ID in a static member variable/property/function, which will be abstract in the base class - just like you described. Once this is done I really don't understand why will I need to get a list of all available article types from a data-source, as you suggest? What I figured would make the most sense is to enumerate through all classes in that namespace, and whichever is inherited from ArticleBase one way or another I'll compare it's article type ID stored as a static member variable/function with the article_type ID from the data store, and by that decide what ArticleBase instance to return.
The same approach I will use to list all possible article types when creating a new article - and then calling other functions to build the input form (or through properties).

Again, my goal is NOT to be able to add new types without recompiling. Rather, it is to have a generic function in the BLL which will not be dependant on an external data-source or hardcoded values to find the relevant Article class based on the unique ID (integer, GUID, string, or whatever) loaded from the data-store. Something like this (C#) will be used in the code loading an article object in the BLL and adding it to an articles list (i.e. GetAllArticles function):

List<ArticleBase> articles = new List<ArticleBase>();
IDataReader dr = myDAL.GetListOfArticles();
while (dr.read()) {
     ...
     int nArticleType = Convert.ToInt32(dr["article_type"]);
     // here we are iterating through all classes in namespace MyCode.AriclesLib
     // and for each class we compare nArticleType with Class::ArticleType(). If equal,
     // we create a new instance of that class and append it to the articles object.
     articles.Add(new CLASSNAME()); // psuedo-code
}

If this will work, I suspect adding a new assembly with the same namespace in it - or perhaps by declaring it's namespace in a config file to be scanned as well for ArticleBase derived classes, will work as well. Again, I'm trying to avoid external lookup tables of any sort.

How do you do those kind of things - when you plan on extending a type you have? The approach I've explained above will require 0 handling once it's properly writted - just create the new class based on the virtual functions you need to overwrite and you're done.
0
 
_Stilgar_Author Commented:
Any ideas?

Can you provide me with a way to iterate through classes derived from a defined base within a specified namespace, and I'll try and create a proof of concept? basically, this is what I'm missing to actually check my idea. This, and perhaps further advice from someone who had faced a similar challenge before.
0
 
_Stilgar_Author Commented:
Thanks, this looks like it. I will be basing a PoC on this and let you know if I have any questions/troubles. In the meantime - enjoy your points :-)
0
 
Alexandre SimõesManager / Technology SpecialistCommented:
Feel free to ask on any trouble.

Enjoy your code! :)

Cheers mate!
Alex
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.