Solved

.NET OOP design question - DataLayer

Posted on 2009-05-17
11
798 Views
Last Modified: 2012-05-07
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.
0
Comment
Question by:_Stilgar_
11 Comments
 
LVL 19

Expert Comment

by:daveamour
Comment Utility
I would look into using an enumeration.
0
 
LVL 14

Author Comment

by:_Stilgar_
Comment Utility
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
 
LVL 30

Expert Comment

by:Alexandre Simões
Comment Utility
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
 
LVL 14

Author Comment

by:_Stilgar_
Comment Utility
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
 
LVL 30

Expert Comment

by:Alexandre Simões
Comment Utility
"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
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 26

Expert Comment

by:Anurag Thakur
Comment Utility
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
 
LVL 14

Author Comment

by:_Stilgar_
Comment Utility
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
 
LVL 14

Author Comment

by:_Stilgar_
Comment Utility
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
 
LVL 30

Accepted Solution

by:
Alexandre Simões earned 500 total points
Comment Utility
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
 
LVL 14

Author Comment

by:_Stilgar_
Comment Utility
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
 
LVL 30

Expert Comment

by:Alexandre Simões
Comment Utility
Feel free to ask on any trouble.

Enjoy your code! :)

Cheers mate!
Alex
0

Featured Post

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

ASP.Net to Oracle Connectivity Recently I had to develop an ASP.NET application connecting to an Oracle database.As I am doing it first time ,I had to solve several problems. This article will help to such developers  to develop an ASP.NET client…
A long time ago (May 2011), I have written an article showing you how to create a DLL using Visual Studio 2005 to be hosted in SQL Server 2005. That was valid at that time and it is still valid if you are still using these versions. You can still re…
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…
You have products, that come in variants and want to set different prices for them? Watch this micro tutorial that describes how to configure prices for Magento super attributes. Assigning simple products to configurable: We assigned simple products…

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now