Reality-Loop

Join Tables and Domain Models

June 20, 2007 | 2 Minute Read
This post was originally posted on my old blog.

In Domain Models arises often a design problem, when there is a relation between two entities and the relation itself holds additional attributes.

As an example a relational model would basically look like this:

Erd

Readings is basically a Join Table between articles and users, but it has additional columns on top of the two obligatory foreign keys.
When designing the associated object-model we are basically forced to create an entity for the reading, since there is no construct for ‘associations with attributes’ in current OO-Languages. But this often leaves a tainted feeling, because readings does not feel like a first-class entity in our model. Often we just want to navigate from articles to users, and for this scenario the reading should be transparent.

ActiveRecord in Ruby offers an interesting construct for this situation:

class Article < ActiveRecord::Base
  has_many :readings
  has_many :users, :through => :readings
end

This allows direct navigation from an Article-Entity to its User-Entities like this:

article.users.each do |reader|
  puts reader.name
end


Now I was thinking of an elegant way to do something similar in C#, when the yield keyword came to mind:

public class Article
{
   private readonly List<Reading> readings = new List<Reading>();
   public void AddReading(User user, DateTime readTime, int rating)
   {
      readings.Add(new Reading(user, readTime, rating));
   }
   public IEnumerable<User> Readers
  {
    get
    {
       foreach (Reading reading in readings)
           yield return reading.Reader;
     }
  }
}

The client code then looks like this:

foreach (User reader in article.Readers)

{

  Debug.WriteLine(reader.Name);

}

Ok, thats just the object model, mapping the whole thing to the database is another topic of its own …