Gunnar Peipman's ASP.NET blog

ASP.NET, C#, SharePoint, SQL Server and general software development topics.

Sponsors

News

 
 
 
DZone MVB

Links

Social

Entity Framework 4.0: POCOs and table-per-type inheritance mapping

In my previous posting Entity Framework 4.0: How to use POCOs I introduced how simple it is to use POCOs with Entity Framework 4.0. In this posting I will refactor my photo gallery model a little bit and introduce you how to implement table-per-type inheritance mapping on Entity Framework 4.0.

Analyzing current model

Let’s start with analyzing the current model shown below. We can see that Album and Photo have some fields in common: Id, Title, Description and Visible. Currently these fields are duplicated to both tables.


Photo Gallery. This is my current very simple model. I made this model so trivial
because it is easier to study new code stuff step-by-step.

I played already with UI a little bit and using separate classes is pretty painful. Also I know I want to add new class to model in near future – my camera is able to make some simpler movie clips and why not to store clips in same system. Clips class will be almost like Photo but there are some more attributes. Adding another class to model in the way Photo is there makes coding more complex. So we need generalization.

GalleryItem class

I created class called GalleryItem as generalization of Album and Photo. GalleryIitem generates ID-s when new gallery item is added. As you may notice the associations on the model are same as before. I don’t want to change them now because currently I have no reason to play them around. My new model is shown on the following image.


Photo Gallery. Album and Photo are now subclasses of GalleryItem. Associations between
Album and Photo are same as before.

Refactoring existing model may be pretty hard headache on Entity Framework designer. It is still same raw and unstable as it has always been. No matter if you refactor existing model or create a new one, here are some guiding resources for you:

Database

To get better idea what is going on take a look at my database diagram. It looks almost the same as my class diagram. Database diagram below shows how to relate tables for table-per-type inheritance mapping.

 

Code

Due to these changes we have to modify also the source code of gallery. We have new class called GalleryItem and we have to change our custom context class MyGalleryEntities. Also Album and Photo have some changes. Let’s look at business classes first.


public abstract class GalleryItem
{
    public virtual int Id { get; set; }
    public virtual string Description { get; set; }
    public virtual string Title { get; set; }
    public virtual bool Visible { get; set; }
}
 
public class Album : GalleryItem
{
    public virtual ICollection<Album> ChildAlbums { get; set; }
    public virtual Album ParentAlbum { get; set; }
    public virtual ICollection<Photo> Photos { get; set; }
    public virtual int ParentId { get; set; }
}
 
public class Photo : GalleryItem
{
    public virtual Album Album { get; set; }
    public virtual string FileName { get; set; }
    public virtual bool IsGalleryThumb { get; set; }
}

Changes shoul be pretty straightforward. Only thing that model before doesn’t reflect visually is that GalleryItem is abstract class. We cannot create instances of it but we can extend it.

MyGalleryEntities class has no more separate properties for albums and photos. There is one property that returns ObjectSet of GalleryItems. We have to base all our queries on GalleryItems collection. Now let’s see new version of MyGalleryEntities class. NB! Don’t forget these two mandatory lines in constructor. Without them your collection and object references are always null.


public class MyGalleryEntities : ObjectContext
{
    private ObjectSet<GalleryItem> _galleryItems;
 
    public MyGalleryEntities() : base("Name=MyGalleryEntities")
    {
        DefaultContainerName = "MyGalleryEntities";

// MANDATORY LINES!!!
        ContextOptions.DeferredLoadingEnabled = true;
        ContextOptions.ProxyCreationEnabled = true;
 
        _galleryItems = CreateObjectSet<GalleryItem>();
    }
 
    public ObjectSet<GalleryItem> GalleryItems
    {
        get { return _galleryItems; }
    }
}

Here are some examples of queries against new MyGalleryEntities.


public void Examples()
{
    var context = new MyGalleryEntities();
 
    var all = from g in context.GalleryItems
              select g;
    var albums = from a in context.GalleryItems.OfType<Album>()
                 select a;
    var photos = from p in context.GalleryItems.OfType<Photo>()
                 select p;
}

Now my gallery made through the first refactoring that touched database, model and source code. Everything works as expected and I can go on with other tasks on my gallery! :)


kick it on DotNetKicks.com pimp it Progg it Shout it

Comments

Jonas said:

Hello Gunnar, This looks really Sweet, I have worked against a table that uses HierarchyId and with the earlier version of EF I noticed that it didint work but now on EF 4.0 I was sure that it worked because I didnt get an error while creating the model from my DB, but when I look at the tables that use HierarchyId I noticed that the modeler have deleted my properties without sending out any error.  :(

Do you know if there are any plan on let the EF handle HierarchyId which are a great datatype.

# October 5, 2009 12:26 PM

DigiMortal said:

No, I have no information about hierarchies in EF4.0. Of course I will blog about it if I find something about it.

# October 8, 2009 9:32 PM