Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
Custom Collections with NHibernate, Part I: Who Cares?

When people speak of the object-relational impedance mismatch, they usually talk about the differences between structure, the lack of behavior in relational databases, and the complexities that mapping abstractions present.  A disadvantage which receives less attention is the impact that the impedance mismatch has on keeping code free of extraneous data-driven communications.  In spite of the efforts taken to avoid it, domain layer code ultimately includes some degree of coding and/or structure which was dictated by the constraints of the data layer.

To illustrate, assume a parent object contains a collection of children objects.  To avoid having the entire object graph loaded from the database all at once, the children objects may be loaded lazily so that they are not pulled from the database until necessary.  One pedagogical approach is to initialize a private collection to null and populate it with a collection of objects when its publicly exposed getter is accessed:

public class Parent { public Children Children { get { if (children == null) { // Init and populate 'children' member } return children; } } private children = null; }

This is a common approach (albeit, not a particularly good one) when using a custom developed data mapper without the use of a service layer.  The problem with this is that seldom does a domain rule exist dictating that a child collection be loaded lazily.  Obviously, loading collections lazily is imperative to the performance of an application and is folly to avoid.  But herein lies the problem; modifications are being made to accommodate a data-layer concern within the domain.  The problem does not easily dissipate with the introduction of object-relational mappers such as NHibernate.  With NHibernate 1.0 and .NET 2.0, it was near impossible to not only code for the data layer, but to include references to NHibernate services directly.  Ayende's, now deprecated, NHibernate Generics was a perfect example of this.  If you wanted to leverage the benefits of generics within .NET 2.0, you had to clutter the domain layer with code which only existed for the support of the data layer.  (But thank goodness he wrote it for us at the time!)

With NHibernate 1.2 and the introduction of native support for generics, Ayende's code was no longer necessary for "out of the box" lists, but a simple solution for leveraging custom collections was still not obvious (to me anyway).  By "custom collection," I mean a collection which extends the behavior of an existing .NET collection(s) with modified or new functionality.  An example would be adding a FindAllByDateRange method onto an Orders collection that is associated with a Customer object.  For this instance in particular (no mean for the pun), you can accommodate the FindAllByDateRange method via four primary routes:

  • The FindAllByDateRange method could be added to a repository object and the database could do the filtering itself.  This is very useful, if not mandatory, for very large collections.  But this also has a few downsides.  A (mostly aesthetic) downside is that moving the filtering to the data-layer grays the layer between the responsibilities of the domain and that of the data layer.  It's a regular occurrence for a developer to ponder if a particular bit of behavior belongs with the domain or with the data layer.  Having many such methods within the data-layer makes it difficult to reuse such functionality in a variety of ways, such as with the specification pattern in the domain layer, and it makes it more difficult for future maintainers to decide where they should put their code.  This is similar to the dilemmas we ran into before ORMs when having to decide how much thinking stored procs should be doing.  My personal rule of thumb is that unless there is an obvious performance reason for putting behavior within the data-layer, then you should lean towards putting it into the domain.  (Yes, I realize that the ICriteria object essentially is the specification pattern; but it is a data-centric tool and feels awkward when used in an otherwise pure domain layer.)
  • The FindAllByDateRange method could be placed onto the Customer object.  In this way, you wouldn't have to do anything special with the Orders collection other than declaring them as an IList<Orders> collection and bind to it in the NHibernate configuration, accordingly.  This approach quickly degrades the Customer object as the single responsibility principle becomes violated over and over again as more and more collection-oriented responsibilities are given to the parent object.  Additionally, this approach now forces the Customer object to have a relationship to every collection that it could conceivably traverse in one association, since it is now responsible for the domain level filtering of those collections.
  • The FindAllByDateRange method could be placed into a wrapper collection which holds a pointer to the collection managed by NHibernate.  This was the approach I espoused in my article, NHibernate (Not So Bad) Practices with ASP.NET.  The following is a code example which demonstrates the technique of wrapping the collection to extend it with additional functionality:
    // Within Customer.cs... public Orders Orders { get { if (ordersWrapper == null) { ordersWrapper = new Orders(orders); } return ordersWrapper; } } private Orders ordersWrapper; // NHibernate binds directly to this member via the access="field" setting private IList orders = new List<Order>(); //////////////////////// // Within Orders.cs public Orders(IList orders) { this.orders = orders; } public void FindAllByDateRange(DateRange dateRange) { // filter the list by date range return ordersFilteredByDateRange; } private IList orders;
    The problem with this approach is that it again necessitates that we modify the domain layer to fit the needs of the data-layer.  It doesn't necessarily introduce anything data-layer specific, but it introduces enough data-driven complexity to lead to increased difficulty in maintainability with higher likelihood for the introduction of bugs.
  • Finally, the FindAllByDateRange could be added to an NHibernate.UserTypes.IUserCollectionType custom collection and treated like a first class citizen, no longer the red-headed step-child that we've been tormenting it as.  (No offense to any red-headed step-children out there!)  The major drawback that people run into with this approach is that the domain-layer usually ends up with a dependency to the NHibernate assembly or to other data-related assemblies to provide the support for the NHibernate custom collection.  But this need not be the case.

Leveraging NHibernate's support for custom collections with the IUserCollectionType interface is the best solution I have found for removing data-driven influences on domain-layer code.  By further leveraging the added benefits of dependency inversion, the domain-layer need not have direct dependencies on NHibernate.dll or any other data-related assemblies.  The intention is to simplify the domain-layer code to something akin to:

public class Customer { public IOrders Orders { get { return orders; } protected set { orders = value; } } private IOrders orders = new Orders(); } public interface IOrders : IList<Order> { IOrders FindAllByDateRange(DateRange dateRange); }

This post is the first of three; the next two will describe the following:

  • Part II:  The Basics.  This post will describe the basics for understanding how NHibernate custom collections are created and managed with a basic working example.
  • Part III:  Refactored.  This post will take the code presented in "The Basics" and separate the responsibilities into appropriately tiered-packages, leveraging dependency inversion, so that the domain layer need not concern itself with data-related dependencies.
  • Part IV:  Extensions.  This final post throws everything out the window and solves the problem using extension methods.  A great approach if you're using .NET 3.0 or later.

Before proceeding with the next three parts, I invite you to review the excellent work which helped lead me to the non-extension method solution that I will be presenting:  http://analog-man.blogspot.com/2007/01/bridge-gap-between-your-nhibernate.html and http://damon.agilefactor.com/2007/07/nhibernate-custom-collections.html.

Billy McCafferty


Posted 12-03-2007 11:49 PM by Billy McCafferty
Filed under:

[Advertisement]

Comments

Sean Chambers wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 12-04-2007 5:44 AM

Hey Bill,

Great post. It's ironic that you should post this because I just posted a question on the nhibernate forum about custom collections with nhibernate in relation to IList<t>.

I find that more often then not custom collections are needed to simplify the domain model by encapsulating constraints on adding/removing data and would be the most logical place to hold said code.

The only problem is that IUserCollectionType is a bit of a pain to implement and most times isn't worth the effort.

In some instances though it is justified and I have used it many times. Thank goodness the folks at nhibernate gave us that option.

Looking forward to the next two parts!

Open Source News » Blog Archive » Custom Collections with NHibernate, Part I: Who Cares? wrote Open Source News &raquo; Blog Archive &raquo; Custom Collections with NHibernate, Part I: Who Cares?
on 12-04-2007 7:24 AM

Pingback from  Open Source News  &raquo; Blog Archive   &raquo; Custom Collections with NHibernate, Part I: Who Cares?

Billy McCafferty wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 12-04-2007 10:57 AM

Without a doubt, IUserCollectionType is a pain to implement.  I hope the approach I'll be presenting will show how much of it may be forgotten and never looked at again.

jphilip@noatak.com wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 12-04-2007 2:29 PM

Thanks Billy,

One question that may be slightly out of context:

To avoid a reference to NHibernate in the Domain layer, I suppose it is also bad to implement ILifecycle, what would be the best alternative ?

Billy McCafferty wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 12-04-2007 2:34 PM

Could you use IInterceptor instead?  If so, that would eliminate the dependency from the domain.  Alternatively, you might be able to interface the object and put the NHibernate dependent version into a data layer, similarly to how I'm doing custom collections.  (I should have the code posted by the end of the week.)  I'm not sure if it can work the same way, though.

DotNetKicks.com wrote Custom Collections with NHibernate, Part I: Who Cares?
on 12-05-2007 9:19 AM

You've been kicked (a good thing) - Trackback from DotNetKicks.com

Pete w wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 12-05-2007 2:01 PM

I have been working on this problem as well...

I'm trying to come up with a collection that inherits from PersistentGenericBag<T>, implements IList<T> but also implements INotifyCollectionChanged.

The last interface is really handy with the WPF data binding features.

Even though I have some working code, I am unhappy with the mappings. for example, I have:

<bag name="Items" inverse="true" cascade="all-delete-orphan" lazy="true"

   collection-type="MyNamespace.DomainList`1[[MyNamespace.Item, MyAssembly]], MyAssembly">

It functions correctly according to the tests, but the mapping leaves something to be desired you see.

Pete w wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 12-05-2007 2:20 PM

In another thought, I was just looking at your two references earlier today.

AnalogMan's post if very informative, but it has some serious flaws, it doesn't have a lazily loaded collection and it sidesteps around this problem by proxying the objects inside of the collection for lazy loading.

Damon's post gave me the best code example, because lazy loading was correctly implemented. Adding INotifyCollectionChanged was easy, but the mapping files have very crude syntax when defining the collection-type... I'm still digging for a better solution, so Im particularly interested in your next few posts this time.

Billy McCafferty wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 12-05-2007 2:40 PM

For the added flexability, the mapping files suffer.  My mapping is 3x worse (literally) than the example that you listed.  It certainly makes it fragile to class name changes, but type errors in the mapping files usually show themselves very quickly; so although it's not strongly typed, it usually fails fast if there's something wrong.  For me, I'm much happier having a more complex HBM and a very clean domain than the other way around.

Tolomaüs wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 12-08-2007 7:52 AM

Hi Billy,

First of all, thanks for the clarifying article.

I think I don't agree with you on a fundamental statement:

"

The FindAllByDateRange method could be added to a repository object and the database could do the filtering itself.  This is very useful, if not mandatory, for very large collections.  But this also has a few downsides.  A (mostly aesthetic) downside is that moving the filtering to the data-layer grays the layer between the responsibilities of the domain and that of the data layer.

"

In my opinion, the repository really is part of the domain. I would define its single reponsability to be the retrieval of a set of business entities based on a specific business requirement.

NHibernate is one of many technologies that provides an implementation for this kind of requirements. So, using the same mindset, I would position NHibernate also as part of the domain. I would even go a bit further and say that, by using an ORM, the clear distinction between the data and the domain layer is lost, it's hidden somewhere in NHibernate' internals. And I'm perfectly happy with that.

Of course you might want to abstract your domain layer away from NHibernate, but that's another subject (and not a very complicated one).

I'm curious on your opinion about this.

Billy McCafferty wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 12-08-2007 10:33 AM

Tolomaüs,

That's an interesting point to bring up.  With newer technologies, the line between data and domain is becoming less clear.  For example, with the introduction of LINQ for Entities, it'll be interesting to see what degree of data/domain separation will be necessary at all.

I feel that the support for unit testing is one of the most compelling reasons to keep a clean separation between the data and domain layers.  If the repositories and NHibernate communications are built right into the domain, it hinders a developer's ability to unit test domain logic without a dependency a live data fitting the requirements of the unit test.  This also requires you to have the database tables and data in place before your unit tests will run successfully.  And if the data changes, the tests start breaking.  Running a large number of unit tests with a live database is also painfully slow.

These factors together result in the singular outcome that developers stop creating, maintaining, and running unit tests whatsoever.  (I speak from painful personal experiences here. ;)

So there are plenty of philosophical reasons for arguing one side or the other, but unit testing is, IMO, the most practical and real-world reason for keeping a clean separation between the data layer and the domain layer.

Adrian Alexander wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 12-12-2007 4:41 AM

A more specific issue I've been working on lately, is to create a set of custom collections that allow NHibernate to work correctly with WPF's data binding.  After studying AnalogMan's example bag collection (which I believe does in fact support lazily loaded collections), I created an improved solution that includes three types (bag, list, and set) of observable collections. See my blog entry ( happynomad121.blogspot.com/.../collections-for-wpf-and-nhibernate.html ) for further details and to download the solution.

PoolDool wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 12-13-2007 3:31 AM

Tolomaüs said,

"So, using the same mindset, I would position NHibernate also as part of the domain"

I think that's absurd. A repository is absolutely not part of your domain (model). And NHibernate even more certainly is not. That's the most ridiculous confusion of domain and persistence layers that I've ever heard.

If your persistence layer is part of your domain, then everything is part of your domain. And so's my wife. We're all part of the domain. Isn't this fun.

Tolomaüs wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 12-15-2007 7:43 PM

Hi PoolDool,

Before you put your mother in the domain, you might want to read the following blog posts first: in.relation.to/.../RepositoryPatternVsTransparentPersistence

tech.groups.yahoo.com/.../6231

Like I said, if you think it's absurd that NHibernate code is leaked in your domain layer, you can abstract it away by using interfaces. Both ways will provide you transparent persistence. So no need anymore for a data layer (or a persistence layer as you call it).

The domain will only depend on the repository interfaces (which are definitely in the domain layer in my world BTW).

NHibernate Custom Collections Supporting Lazy Loading with IPersistentCollection & DomainPersistentGenericBag « damon wilder carr cto agilefactor wrote NHibernate Custom Collections Supporting Lazy Loading with IPersistentCollection &amp; DomainPersistentGenericBag &laquo; damon wilder carr cto agilefactor
on 12-23-2007 12:57 AM

Pingback from  NHibernate Custom Collections Supporting Lazy Loading with IPersistentCollection &amp; DomainPersistentGenericBag &laquo; damon wilder carr cto agilefactor

NHibernate Custom Collections Supporting Lazy Loading with IPersistentCollection & DomainPersistentGenericBag « damon wilder carr cto agilefactor wrote NHibernate Custom Collections Supporting Lazy Loading with IPersistentCollection &amp; DomainPersistentGenericBag &laquo; damon wilder carr cto agilefactor
on 12-23-2007 1:35 AM

Pingback from  NHibernate Custom Collections Supporting Lazy Loading with IPersistentCollection &amp; DomainPersistentGenericBag &laquo; damon wilder carr cto agilefactor

NHibernate Custom Collections Supporting Lazy Loading with IPersistentCollection & DomainPersistentGenericBag « damon wilder carr cto agilefactor wrote NHibernate Custom Collections Supporting Lazy Loading with IPersistentCollection &amp; DomainPersistentGenericBag &laquo; damon wilder carr cto agilefactor
on 12-23-2007 5:50 PM

Pingback from  NHibernate Custom Collections Supporting Lazy Loading with IPersistentCollection &amp; DomainPersistentGenericBag &laquo; damon wilder carr cto agilefactor

Custom Collections with NHibernate, Part III: Refactored - Billy McCafferty wrote Custom Collections with NHibernate, Part III: Refactored - Billy McCafferty
on 12-28-2007 3:31 PM

Pingback from  Custom Collections with NHibernate, Part III: Refactored - Billy McCafferty

Custom Collections with NHibernate, Part II: The Basics - Billy McCafferty wrote Custom Collections with NHibernate, Part II: The Basics - Billy McCafferty
on 12-28-2007 3:31 PM

Pingback from  Custom Collections with NHibernate, Part II: The Basics - Billy McCafferty

Bill wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 01-04-2008 1:31 PM

Everytime I read your work, I feel like I'm A) learning and B) taking crazy pills.  I totally understand the want for smarter nHibernate collections (easy databinding and such).  But I want it to write less code!!  So when dependency-injection interfaces for ideological seperation-of-concern concerns start being required, I prefer to KISS your suggestions goodbye.

Billy McCafferty wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 01-04-2008 1:53 PM

That was the most entertaining criticism I've yet received! ;)

IMO, the pattern of separated interface (i.e., coding to interface with dependency injection) has an enormous number of applications beyond simply wrestling NHibernate into submission.  For example, it's a clean way to separate repository logic from business logic without denying access to those repositories from the domain layer.  This is really only applicable if you're unit testing your code or are concerned with the idea of separation of concerns.

Separated interfaces are also immensely helpful when integrating third party systems; e.g., Palisade @RISK for performing complicated risk analysis (which I'm using in a current project).  Your domain layer would house interfaces to communicate with @RISK, but it wouldn't hold any direct references to this third party application.  Another assembly would be developed to contain the @RISK-specific integration code as well as the references to the third party application.  Dependency injection techniques (with or without an IoC container) would then be leveraged to inject the @RISK integration code into the domain layer in the production code.  Doing this provides three major benefits:  you can unit test all your domain logic with mocked @RISK objects in order to isolate integration code from your domain logic, one develop can focus on the domain logic without having to know any of the internals of the @RISK integration code (other than the interfaces defined and provided by the "integration expert"), and the entire development staff doesn't have to install the third party tool in order to have the solution compile on their own machine.

I've been on *many* projects without the use of separated interfaces (or its equivalent), and all of them have suffered greatly with logically separate layers bleeding into one another.  Just a tiny bit more of coding up front can go a long way in preventing a lot of ugly maintenance down the road.

Hadi Hariri wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 01-09-2008 12:29 PM

Bill,

Here's an issue I'm having. I'm just starting out with NHibernate and I'm debating whether I should have a façade for my DAL that encapsulates NH, for the reason of making my BL agnostic to data access, but also because there are certain data routines that I require that do not necessarily use NH, and I want them to be encapsulated correctly. My concern is if I have to end up making proxy calls for all the stuff I need in NH. Looking at this tutorial (http://tinyurl.com/2jwd3u), it doesn't give me good vibes how he's made a db manager.

Billy McCafferty wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 01-09-2008 1:21 PM

Hadi,

The approach I've been using for the last two years, which I'm still very happy with, is described in detail at www.codeproject.com/.../NHibernateBestPractices.aspx .  (I need to update it to reflect the custom collections advice here, but otherwise, it's fairly solid.)

Feel free to post questions on the forum board there.

http://devlicious.com/blogs/billy_mccafferty/archive/2007/12/03/custom-collections-with-nhibernate-part-i-the-basics.aspx wrote http://devlicious.com/blogs/billy_mccafferty/archive/2007/12/03/custom-collections-with-nhibernate-part-i-the-basics.aspx
on 03-22-2008 2:56 AM
Cialis. wrote Taking viagra with cialis.
on 07-16-2008 11:54 PM

Multiple orgasms through cialis. Drug called cialis. Cialis best price buy online. Cialis.

Marty wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 08-20-2008 12:49 AM

Whats is wrong with this?

Customer

{

IList<Orders> GetOrderInDateRange()

{

 return DataFactory.GetCustomer().GetOrdersInDateRange(range);

}

}

This removes the dependency for specific DAL code in the domain.

Billy McCafferty wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 08-21-2008 7:31 PM

Marty,

Your solution will work just fine but doesn't fall in line with my 2nd bullet point above, "The FindAllByDateRange method could be placed onto the Customer object..."  To me, it goes a bit outside of the single responsibility principle, although works just fine from a practical standpoint.

There's a much easier way to do all of this in .NET 3...I'll be posting part 4 of this series in the next few business days.

Custom Collections with NHibernate, Part IV: Extensions! - Billy McCafferty wrote Custom Collections with NHibernate, Part IV: Extensions! - Billy McCafferty
on 09-03-2008 7:28 PM

Pingback from  Custom Collections with NHibernate, Part IV: Extensions! - Billy McCafferty

Wtvm wrote Wtvm
on 04-03-2009 7:00 PM

... this member knows that I have just completed my brand new guide to article writing to ghost writers, make sure that you can do this right, and as search words. went through the use of ga school closings or word count, they would like to cover and

Pharmg225 wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 06-19-2009 1:02 AM

Very nice site!

Pharmd278 wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 07-30-2009 9:16 PM

Very nice site!

Pharmd109 wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 08-08-2009 7:59 PM

Very nice site!

Pharmk747 wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 08-12-2009 2:40 AM

Very nice site!

Pharmf770 wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 08-12-2009 2:40 AM

Very nice site!

Pharmk379 wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 08-21-2009 12:29 AM

Very nice site!

Pharmk980 wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 09-13-2009 12:54 PM

Very nice site!

aeLZOWxt wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 11-19-2009 11:19 AM

Hi! wVPzSd

Pharmb936 wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 11-27-2009 6:50 AM

Very nice site!

Pharme383 wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 12-29-2009 9:42 AM

Very nice site!

Pharmd734 wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 01-13-2010 4:46 PM

Very nice site!

Pharme674 wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 01-31-2010 6:19 PM

Very nice site!

BnBfZw wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 03-19-2010 7:39 AM

NBOzjzx

Pharmf114 wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 03-30-2010 7:40 PM

Hello! ddebeak interesting ddebeak site!

Pharmg890 wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 11-18-2010 1:27 PM

Hello! kacfkec interesting kacfkec site!

Pharma822 wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 11-18-2010 4:32 PM

Hello! ceecckk interesting ceecckk site!

Pharmd493 wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 11-27-2010 12:12 AM

Hello! dckdeae interesting dckdeae site!

Pharmd871 wrote re: Custom Collections with NHibernate, Part I: Who Cares?
on 11-27-2010 6:55 AM

Hello! adkekkd interesting adkekkd site!

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)