A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.
I'm creating a reasonably small (just me, ~6 weeks) and independent module of a web-based enterprise application in ASP.NET with C# back-end code. I'm attempting to develop it cleanly, with a good object-oriented back-end layer. Right now, I have a Domain Model of part of the system set up. The classes in the Domain Model are also Active Records; this might not work perfectly, but I'd prefer not to have to expose certain data in the Domain Model in order for a Data Mapper to be able to access it. I am also using Unit of Work to track what objects have been created/changed/deleted.
The specific part I'm working on now has a collection of Branch objects. Each Branch may contain from 0 to 7 Division objects. From the other side, a Division must belong to a Branch; more specifically, when inserting a Division into the database, it must have a valid Branch ID.
The problem comes with creating these objects. When I create a Division, I could require that a Branch be provided in the constructor, or provide a way to set the Branch and require that it be set before inserting, or I could have a method on Branch to create a division and suggest using that (although I see no way to enforce this without friend classes).
Furthermore, the Unit of Work simply contains collections of abstract domain objects; I'm not sure how to deal with these dependencies so that the Branches get inserted before the Divisions that depend on them. It would be good enough to order them simply based on class (i.e. all Branches before all Divisions) but this must be extensible since there are various other dependencies of this sort in the system.
Basically, what can I do to deal with dependency issues in Domain Model and Unit of Work?
A simple list of the design patterns I refer to can be found at http://martinfowler.com/eaaCatalog/
Wednesday, December 14, 2005
One approach would be to separate everything out into domain objects and relationships between those objects. So, in addition to having a Branch object and a Division object, you'd also have a BranchDivisionRelationship object used to form a relationship between them.
This solves the problem of dependency by breaking it. When you insert, always insert all of the objects followed by all of the links, and you won't have any trouble. Similarly, always Delete the links first and then the objects.
This also allows you to create Branch objects and Division objects without worrying about immediately establishing the relationship between them. As long as the relationship has been created by the time you are ready for the commit, you should be all right.
This kind of approach makes the structure of your domain model a lot more regular since objects aren't concerned directly with other objects - the links take care of that. It does make your table structure a little more complicated since it adds in an extra layer of Join operations.
Wednesday, December 14, 2005
If a division requires a branch, then I'd do a couple of things. First, the Division constructor requires a Branch object; don't let the user construct a Division without the Branch. Second, have the division check "Is my branch in the database?" If not, have it save the Branch out first.
I tend to give my domain objects a dirty flag, which is set on first construction and later on any mutation. Writing back to the database clears the flag. So, this way in my Division.Save() method I can just do:
... write division to db ...
If the Branch is already in the database (not dirty) nothing happens with the branch. If, on the other hand, the branch is dirty (new or updated) this guarantees that the changes to the Branch go into the database first.
This obviously isn't as clean with many-to-many relationships, 'fraid I don't have a good answer for that one.
In my experience UnitOfWork for different types can't/shouldn't be implemented in a single class like described in Fowler. While the UnitOfWork knows what objects are dirty, etc., it really has no idea how or in what order to commit them. Topological sort indeed. I think this is one of the bigger cop-outs in an otherwise stellar book.
Since you're using ActiveRecord, what I would do is put the responsibility for updating Divisions inside the Branch class and only track Branches in UnitOfWork. Since a Division can't be inserted without a Branch, Division doesn't have to be an ActiveRecord. It could remain so, i.e. Update(myParentBranchID)
If a Division gets dirty let it notify its Branch parent and let the Branch go dirty. The ActiveRecord implementation in Branch will figure out what needs doing.
This topic is archived. No further replies will be accepted.Other recent topics
Powered by FogBugz