9

Okay, so we have a utility here in-house that generates business-model classes from our database tables and views, similar to (but not quite exactly like) an ORM. In maintaining it, it occurred to me that the data in the schemas isn't likely going to change a whole lot. The functionality, however, might. We may want to add additional functionality down the road. We may want to generate some of that functionality, and we may want to extend it.

The classes we're building will reside in a class library for consumption by other libraries and applications. No big surprise there. But the stumper here is how to design generated classes in such a way that we disrupt as little code as possible when we regenerate a class. If, for example, code has been added to a property (which represents a column in a database table), we don't want to lose that.

So, there are two approaches that leap to mind:

Classic inheritance, where the entire thing is done in a single, "monolithic" class and consumers are free to override the base implementation. This gets kind of tricky from time to time, though, and frequently introduces casting headaches. Further, if the derived class isn't careful and forgets to invoke base class functionality, things can quickly go awry.

Partial classes. In this scheme, we separate the business object into distinct parts: the properties (which map to columns), and the behaviors. Behaviors could even be broken down further into generated behaviors and custom behaviors. The problem with this approach, as you can see, is its inherent complexity. Further, there's the naming problem.

Here's my question for you folks: When you're dealing with a scenario like this (if you ever have), or if you were presented with a scenario like this, what solutions would you consider, and why?

Mike Hofer
  • 16,477
  • 11
  • 74
  • 110
  • 1
    Just to comment on the naming problem - my experience with code generation tools is that they usually just generate one big file with all your classes in it. This lets you just put your custom code into class files that are named after your class, and usually we comment the header to make it more obivous that there is generated code elsewhere. – womp Jun 26 '09 at 18:57
  • I disagree with this approach. Long term developers will be maintaining code in two different files and short term developers are subjected to changes outside of their control (If you limit the recreation to a specific schedule would be helpful). Good luck. –  Jun 26 '09 at 19:38

5 Answers5

13

The whole reason Partial Classes are included in .Net is to make it easier to utilize code generation tools.

If you are generating code, use partial classes. It's really that simple. Why would you take the risk that the code might have to be re-generated down the road and you'd have to do a ton of work to re-update it with customizations?

I don't find there is much complexity to partials either - it's simply one class split over multiple files. Generated code in one file, custom code in the other.

womp
  • 115,835
  • 26
  • 236
  • 269
4

I would go partial classes path. Just because it fits more natural for dividing 1 object in many parts. Even Linq2Sql uses partials. Fight with complexity with patterns and proper conventions. And it's easier to perform 'partial update' (if generated code is well structured) on partial classes.

If you aren't doing any code generating - go class inheritance way (actually, you would be forced to, cause partials won't work across different assemblies).

Arnis Lapsa
  • 45,880
  • 29
  • 115
  • 195
3

This is exactly the problem that partial classes exist to resolve. I think you may be breaking them down a little too far for practical purposes though. My gut reaction without knowing the finer details of your application would be to use a partial class file for all the generated code of a class, and a second file for all the code created by hand. Come up with a naming convention for generated partial classes and stick with it.

Matthew Vines
  • 27,253
  • 7
  • 76
  • 97
  • I would never do this. When you recreate all the partial class for all the DB changes, your entire code base could or probably will be broken. Partials was added mostly for the designers, and are a hack for a bad design IMO. –  Jun 26 '09 at 18:07
  • 6
    I disagree entirely. I personally am not a big fan of code generation, but partial classes are the only way to go about it. You MUST have a mechanism of regenerating the code you want auto generated without touching the rest of your classes code. Partial classes are by far the best solution to that problem. – Matthew Vines Jun 26 '09 at 18:12
  • 2
    Also if done correctly, no regeneration of a partial class should break your codebase. Due to the magic of encapsulation. You can and should have your auto generated code conform to an interface that your classes implement. The most likely changes (adding a field, changing a data type, etc.) Will not break your class's contract. – Matthew Vines Jun 26 '09 at 18:16
  • Agree with Matthew. Partials serve an extremely useful purpose, and IMO are more likely than not to be representative of a really good design. – womp Jun 26 '09 at 18:23
  • For the short term, initial development I would agree more (but then you have several files which can be a maintenance hazard also). But long term (maintenance) this should be done manually. If I recreated say 500 partial classes, that could have a huge impact on the code. –  Jun 26 '09 at 18:29
  • 2
    I think you're overstating the impacts. The whole point of partials is that you *don't* impact your codebase when you regenerate classes. We have a build process that regenerates a set of classes from an XML schema on every single build. The schema changes with every feature addition. We have not had to touch the partial classes in two years. – womp Jun 26 '09 at 18:33
0

You say:

similar to (but not quite exactly like) an ORM

I would draw up some forecats figures around maintenance costs for the current solution (which I'm guessing is significant) then select an ORM, write a proof of concept solution and draw up comparative figures for maintaining that. I'm not sure what this custom package costs in the way of maintenance, rampup and developer buy in but I for one would not go anywhere near a "custom" product such as this. The knowledge is not transferable, the risk of error is high (always the case with code generation) and you are bound to the intracacies of the underlying database.

SteveK
  • 1
  • 2
    You realize this question is from 2009, right? At any right, I opted for the partial class route, and it worked marvelously well. The tool we developed was extremely well documented, and we had no serious issues with it. (Neither I, nor any developers who came after me.) – Mike Hofer Jul 03 '12 at 14:37
0

If you have a type that is to be serialized (to xml) and want to add some functionality, you have to use partial class and not inheritance. Thanks ///M

Mats
  • 1