On Updating Records with Object (Non)Relational Mappers in F#

I’m delivering a talk on NoSQL and F# at the F# User Group in Cambridge, MA in a few weeks. As I started prepping my old C# and NoSQL presentation for an F# makeover, it didn’t take long for me to find some critical differences that more or less fly in the face of common ORM patterns.

The fetch-modify-update idiom is often used when dealing with updates to a record. If you consider a form where an Artist record may be edited, the (web) workflow is typically to:

  1. Fetch the record for display on an edit form
  2. Re-fetch the record when changes are submitted
  3. Update any properties that were changed by the form (perhaps with MVVM and AutoMapper)
  4. Save the record that was fetched and updated

In abbreviated code, this might look like:

var artists = _mongoDatabase.GetCollection(COLLECTION);
var artist = artists.Find(Query.FindOne(Query.EQ("_id", id)));
artist.Name = viewModel.Name;
artists.Save(artist);

This pattern works well with ORMs such as the Entity Framework and NHibnerate. It also works with O(Non)RMs such as the MongoDB C# driver, which is shown in the code above. Again, the idea is to retrieve a record, modify some properties and save it back to the database, whether relational or NoSQL. However, this pattern breaks one of the core functional programming concepts, namely immutability.

As I sat down with the F# equivalent of my NoSQL demoware, I had a choice to make. I could take advantage of F#’s multi-paradigm language features and simply allow for mutable Artist instances or I could work through the problem using immutability. I chose the latter option, which I’ll describe below. But first, I’ll note that this post is certainly geared towards C# developers who are new to F#. F# developers probably don’t get too hung up on value bindings vs. variables as I do.

The code in F# is still only 4 lines, but there are a couple of notable differences.

let artists = mongoDatabase.GetCollection("Artists")
let artist = artists.Find(Query.FindOne(Query.EQ("_id", id)))
let updatedArtist = { artist with Name = viewModel.Name }
mongoCollection.Save(updatedArtist) |> ignore

The requirement that artist be immutable leads to the use of an F# record. An F# record is sort of like an anonymous class in C# (no constructor or methods), but it has a name and has built in facilities for copying one record to another. That copying facility is what is demonstrated on the third F# line. The updatedArtist value is a member for member copy of the artist, except for the Name property that is set to the view model’s name property.

type Artist = { Name : string; Genre : string; Id : ObjectId }

Records seem to work particularly well with ORMs and O(Non)RMs where POCOs are used to represent database records, whether documents or table rows.

This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>