tags:

views:

130

answers:

2

I have a complex domain model built on top of a legacy system that I've built most of the "get" methods for - typically just by passing around database primary key IDs. Easy enough. I'm now curious how to approach the task of creating new objects in the database and saving existing ones with new data and want to make sure I cover all my bases.

The main domain objects that correspond to entities in the database number around 20-25 for the entire project. About 10 or so will need to be saved (the rest are just there for supporting data and don't need updating by the user). The objects to be saved have complex dependencies - object A has a list of object B which contains objects C, D, and E, for example, all of which might need to be saved when the original object A is.

I'd like to build it so it's easy to use by the UI developer, but also enforces that only valid data gets saved (let's say maybe object B cannot save unless object C is in a valid state). This makes me shy away from allowing them to create an object from scratch and attempt to save it - I want to follow the principle that objects should only ever be alive in a valid state.

The other alternative is exposing "CreateNew" and "Save" methods on the service objects that handle them, but the parameter list for such methods would be egregious.

I'm thinking of requiring "CreateNew" and "Save" to accept something like a command object that they can create and pass so they know exactly what data is needed and what they can't try to control. I read up on the command pattern but I don't need any of the main perks it provides.

What considerations should I have to decide on an approach? This is C#3.5, if that factors into it at all.

+1  A: 

You can make your objects all expose the same method, call it AttemptSave, and calling this method on the parent object will result in it calling in cascade those methods of all children.

The method could return a boolean value indicating the success of the operation. No need to throw exceptions to make it easy for the UI developer.

Then expose a method GetValidationErrors. If AttemptSave returned false, then the UI developer should call this method to retrieve and display errors.

Alternatively, you can add a validation method Validate which will precheck the object hierarchy. You can return validation errors via GetValidationErrors. Then the call to AttemptSave will be performed. Should it fail, you can return the errors with GetOperationErrors.

Something in the philosophy of SQL. Either your query succeeded or not, you can always look at @@ROWCOUNT to get an idea whether the query did at least part of the job.

Developer Art
+1  A: 

You should investigate the popular object-relational mapping frameworks for .NET. A lot of people have handled this problem before, and some of the smartest ones have shared the fruits of their labor with us. They've got loads of features and the most popular ones are heavily tested.

Every few days, it seems, someone new asks for .NET ORM recommendations, so there are plenty of Stack Overflow topics to help guide you. For example:

(If you search on 'ORM' and '.NET' you'll turn up many many more matches.)

In typical usage, the UI developer only deals with high-level parent objects (called 'aggregate roots' in the language of Domain-Driven Design). They use the ORM as a Repository and it ensures all the operations in a given Save are bundled together in sensible transactions. (You still need to enforce validity per business rules in your domain objects.)

Here's a simplified look at what UI code would look like:

// Given an IRepository implemented by your ORM,
ICustomer customer = repository.Get(customerId);

// ... do stuff to customer and its child objects ...

repository.Save(customer);
Jeff Sternal
I thought about checking them out, but a problem comes up with the "legacy system" part: though I can read from the database at will, it must pass through a web service when saving back. It can't write directly to the database, sadly.
Chris
Hmm, unfortunate. I don't have any experience with that, though someone asked a question about it here, which might be interesting: http://stackoverflow.com/questions/1202178/incorporating-orm-into-a-semi-soa-architecture.
Jeff Sternal
Nice find, had been looking for a link like that. Thanks!
Chris