Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Your domain model contains a set of objects. I'm here presenting a side project, but I have a much more complicated work project falling to its knees because I didn't do a good separation of the database and the domain.

In this case, the object is called a CyclingRecord.

Following Onion Architecture, the domain objects know nothing of their persistence. However, each one of those objects corresponds to an entry in a datastore (potentially a database, potentially a file). The row ID is absolutely not part of the domain object and therefore has no business being stored in the domain object.

data CyclingRecord = CyclingRecord { date :: Day,
                                     distance :: Float,
                                     time :: Integer,
                                     description :: Maybe String }

In a language that enforces strong immutability (such as Haskell and Clojure), identity and value are synonymous. Further, there is no reason why you could not record more than a single ride in a day. So, the entire record completely describes a ride.

So, if I edit a record in the Domain, when I pass the edited objects back to the Database Infrastructure, how do I go about notifying the database that it needs to update a particular record instead of deleting an existing record?

(the same idea would need to be extensible so that I can have an application potentially manipulate many records at once and then send them all back to the database. Offline operation or syncing or just avoiding excessive disk activity)

Unless the correct answer is to actually make something like a unique identifier for each ride. Perhaps a UUID. Perhaps add a "day counter" to the record. Make it intrinsically part of a bike ride and then have the database depend on it instead of a separate row ID.

share|improve this question

4 Answers 4

up vote 2 down vote accepted

The correct answer is to make something like a unique identifier for each ride. Entities need identity which, in this case, really is separate from the combination of date, distance, time, and description. You are saying these things can change, while the identity cannot.

So, give them something immutable -- a UUID, if you like.

share|improve this answer

Looks like your timestamp should be unique, why not use that as your primary key? In your persistence logic you can either pre-delete (always delete any records with the same timestamp, then insert) or check to see if a record already exists and insert or update as appropriate.

Alternately, you could use some sort of decorator or companion object to hold the persistence metadata. Your persistence logic would have to have some way to match the metadata with the cycling record and create or update it when persisting the record.

If you determine you really need a unique ID, why not assign a "ride number"? That sounds like a reasonable thing to record. It could be either a sequential number, or you could produce it from the timestamp (e.g., "201205011045" for a ride you took at 10:45 on 1 May 2012).

share|improve this answer
3  
Never use a timestamp in the hope it will be unique. Oh god, the pain I've seen when that rule was broke! –  Ian May 1 '12 at 19:04
    
Yeah, ordinarily I wouldn't recommend that, but in this case it seemed appropriate (given that it's a low-volume single-user data store). –  TMN May 1 '12 at 19:07
    
@TMN I did not even consider the possibility of a multi-user data store until much after posting this question. If I want to support that, I think I would have to create something like a UUID. –  Savanni D'Gerinel May 1 '12 at 19:42
    
Well, you wouldn't have to, you could simply have a composite key composed from a user name and the timestamp, but it's certainly cleaner to have an artificial ID (and what I'd recommend in anything but a hobby/homework application). –  TMN May 2 '12 at 13:33

If your database has a unique identifier, there is no reason not to include that as part of the domain model. Even if it does not have any other meaning (e.g. Employee Number, username, email address, automobile VIN, etc.).

Otherwise you have to rely on some other combination of fields or rely on every object to have some unique number assigned to it in the real world.

This is key with updating or deleting data (You can theoretically select a record by any other number of fields exactly as a user would in a search form.). Immutable objects don't have this problem with getting updated.

share|improve this answer
  • Persistence independence (or ignorance, I can't remember correct term) is difficult and sometimes impossible to achieve with certain technologies. E.g. (LINQ to SQL in a .NET technology stack is a no-no as it fully relies on the database structure). If that's the case, then you have to accept that and live with it.

  • There is nothing wrong with adding unique identifier to your domain model. If it makes you happier, than you can create an annotation to denote that annotated attribute isn't part of a domain model.

  • Regarding checks to see if the object has changed, you can add a timestamp column. This is relatively cheap. You would have to implement object state tracking or choose a persistence framework that can already do that for you.

  • Alternative to state tracking is to check all properties to see whether they have changed, but this is not enough on its own.

  • My question to you is whether you can justify such a strong need for complete persistence independence? Seeking perfection is good, but you have to draw a line sometimes.

  • Finally, the majority of your problems can be partially if not fully solved by existing data persistence frameworks.

share|improve this answer
    
Oh, I would break purity if I needed to in a real project. This is a small application just big enough to give me some real information. I can use it to figure out what I should be shooting for in large-scale code. –  Savanni D'Gerinel May 1 '12 at 19:54

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.