views:

95

answers:

2

Okay, the title is not saying too much, sorry. Essentially it's an Architecture Question about an Application that can have multiple database backends (Well, "Database" is loosely used here as it can mean anything from MSSQL to XML Files to an IList in Memory), essentially involving the Repository Pattern.

I have a set of POCOs that essentially just serve as Data Transfer object (DTOs) and therefore do nothing except carry data. Unfortunately, I am seeing myself in the need to decorate them with Attributes i.e. for use with certain ORMs or even for use with the XmlSerializer. That means that they are now somewhat bound to the database layer and in my opinion not simple POCOs anymore.

From what I see, I would now have to duplicate these DTO-Classes, so that I have one Database-Specific class with Attributes and whatever I need, and a second version that is generic through my application. My Model would then have to convert them (which is where something like AutoMapper could be used)

It just still "feels weird" as I am essentially duplicating all my DTO Classes, yet the existence of Object-To-Object mappers seems to indicate that this is perfectly fine. Also, this seems to copy the ADO.net Approach whereas there is a Generic Part (down to the DataSet) and a Database-Specific part.

Is that correct? Or is there a different approach?

+1  A: 

In the (somewhat limited) case of only needing to add Attributes for use with a given ORM, it is possible to write a wrapper that adds these things at runtime. You could add such code to the ORM constructor (subclassing the ORM or ORM initialization class as necessary), or to an ORM-initialization event.

An example is given below for tagging three properties with an attribute using Reflection, but it could be easily modified to add attributes to a type, or to all properties, etc.

 PropertyDescriptor[] properties = TypeDescriptor.GetProperties(this);
 //Add as necessary
 string[] propertiesToTagForORM = { "Name", "Category", "Description" };

 foreach (string propname in propertiesToTagForORM)
        {
            PropertyDescriptor prop = properties[propname];
            if (prop != null)
            {
                AttributeCollection runtimeAttributes = prop.Attributes;
                // make a copy of the original attributes 
                // but make room for one extra attribute
                Attribute[] attrs = new Attribute[runtimeAttributes.Count + 1];
                runtimeAttributes.CopyTo(attrs, 0);
                attrs[runtimeAttributes.Count] = new BrowsableAttribute(false); 

                prop = TypeDescriptor.CreateProperty(this.GetType(), propname, prop.PropertyType, attrs);
                properties[propname] = prop;
            }
        }
}

Adapted from here. Just an idea - this is probably the first direction I'd head :)

JoshJordan
That's an interesting idea. Essentially I could have my backends as separate assemblies and have them Manipulate the POCOs as needed... I'd definitely remember that approach.
Michael Stum
Indeed. If you try it, it'd be useful to have feedback on how it worked out for you. Do post here if so.
JoshJordan
A: 

You should ask yourself what goes wrong when you include those attributes in your POCO's. Especially if your POCO's do nothing more than carry data and do not serve as a domain model with business logic, which you would like to keep separate form "technical details" exposed in attributes. In that case the only drawback of those attributes seems a little leakage of technical details of lower levels to higher levels. But does that justify a whole new layer in which you do nothing more than "stupid attribute copying". I would probably say not.

In short: always think carefully whether the solution to a perceived problem does not cause a whole other (and maybe even bigger) problem of its own. I myself wouldn't worry too much about those attributes in the case you illustrated. If anything, I would rather look for options to keep the attributes out of the POCO's and put them in other resources (classes or config files) than to introduce the extra transformation layer.

Pascal Lindelauf
I just think that they might be messy if I have 3 or 4 different "sets" of metadata on them, that was my concern.
Michael Stum
I understand, but do carefully consider what the *actual* extent of the mess will be and if adding extra transformations and classes will not just make things even messier and more complex. I've seen too many projects that rather mindlessly resorted to DTO's, which in hindsight did not add any value, but did create great maintenance overhead. In these cases I'm really tempted to call YAGNI until proven otherwise.
Pascal Lindelauf