Solved

.NET OOP design question - DataLayer

Posted on 2009-05-17
11
802 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
ID: 24409548
I would look into using an enumeration.
0
 
LVL 14

Author Comment

by:_Stilgar_
ID: 24410150
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
ID: 24410175
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
Master Your Team's Linux and Cloud Stack!

The average business loses $13.5M per year to ineffective training (per 1,000 employees). Keep ahead of the competition and combine in-person quality with online cost and flexibility by training with Linux Academy.

 
LVL 14

Author Comment

by:_Stilgar_
ID: 24412446
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
ID: 24413915
"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
 
LVL 26

Expert Comment

by:Anurag Thakur
ID: 24414054
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_
ID: 24415032
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_
ID: 24431937
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
ID: 24432916
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_
ID: 24462841
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
ID: 24462931
Feel free to ask on any trouble.

Enjoy your code! :)

Cheers mate!
Alex
0

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction This article shows how to use the open source plupload control to upload multiple images. The images are resized on the client side before uploading and the upload is done in chunks. Background I had to provide a way for user…
Real-time is more about the business, not the technology. In day-to-day life, to make real-time decisions like buying or investing, business needs the latest information(e.g. Gold Rate/Stock Rate). Unlike traditional days, you need not wait for a fe…
Nobody understands Phishing better than an anti-spam company. That’s why we are providing Phishing Awareness Training to our customers. According to a report by Verizon, only 3% of targeted users report malicious emails to management. With compan…

839 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