Entity Framework and Interface issues

There is, and has been for quite some time a serious issue with Entity Framework – namely that it doesn’t support complex interfaces.

A simple entity based on an interface such as this is fine

public class Root : IRoot
{
public int RootId { get; set; }
public string Data { get; set; }
}

However as soon as your start to introduce child objects, for example an
ICollection Leafs
well now we have an issue, because the interface needs to define the collection as
ICollection Leafs
and that’s where it all goes a bit pear-shaped because EF can’t figure out that Leafs is a navigation property because it’s based on an interface instead of a concrete type.

I have spend many a wasted few hours searching for a fix to this, the majority of the articles I find simply state that EF does not support Interfaces.

In the past I’ve worked around it by using a DTO, so basically my DTO class is what EF will use to create my database mappings, but I then need to use something like AutoMapper, or roll my own mapper in order to convert my DTO to a concrete class based on an interface and vice versa.

This also has the issue that although retrieving and adding NEW entities works OK, as soon as you try to do an update to an existing entity with Attach it all starts to fall apart again.
Once again I managed to fixed this by simply ensuring that when I’m mapping from my concrete to the DTO I get the EXISTING DTO from the database, and then loop through all it’s properties copying and updating as required.

So recently, in a fit of despair, I sat down and hammered out a way to find an alternative solution that was a bit more elegant.

OK, so first we have our standard interface thus:

public interface IRoot
{
string Data { get; set; }
System.Collections.Generic.ICollection Leafs { get; }
int RootId { get; set; }
}

So we have an interface properly defined, but EF doesn’t know how to get the navigation property. So we need to create one along side our Collection that the interface expects, so lets go with

public ICollection Leafs { get; set;}
public ICollection LeafNavigation {get; set;}

OK that’s great but now of course these are two separate lists, so we’ll add an internal list and connect our two ICollections up to it. We’ll also ass some constructors for good measure.

public class Root : IRoot
{
private List _leafs;

public Root(ICollection leafs) {
this._leafs = leafs as List;
}

public Root(List leafs)
{
this._leafs = leafs;
}

public Root() {
this._leafs = new List();
}

public int RootId { get; set; }
public string Data { get; set; }

public ICollection Leafs { get { return _leafs.ConvertAll(l => (ILeaf)l); } }

public ICollection LeafNavigation { get { return _leafs; } set { _leafs = value.ToList(); } }
}

So now EF is happy, we’ve implemented the interface so we can use IRoot rather than Root. But now we have another issue – basically I can’t seem to ADD Leaf Entities to IRoot.Leafs – maybe someone can point out what I did wrong – because although the code lets me add the leaf with

IRoot root = new Root();
root.Add(new Leaf(){ Data="Some data"});

it just does’t actually ADD it to the underlying collection (I’ve tried a number of permutations – like I said if I have done something obvious PLEASE let me know!)

Anyway, I managed a simple work around – basically lets just add and Add method to the actual class that takes a Leaf and adds it to the underly connection thus the finished class and interface look like this.

public interface IRoot
{
void AddLeaf(ILeaf leaf);

string Data { get; set; }
System.Collections.Generic.ICollection Leafs { get; }
int RootId { get; set; }
}

public class Root : IRoot
{
private List _leafs;

public Root(ICollection leafs) {
this._leafs = leafs as List;
}

public Root(List leafs)
{
this._leafs = leafs;
}

public Root() {
this._leafs = new List();
}

public void AddLeaf(ILeaf leaf) {
_leafs.Add(leaf as Leaf);
}

public int RootId { get; set; }
public string Data { get; set; }

public ICollection Leafs { get { return _leafs.ConvertAll(l => (ILeaf)l); } }

public ICollection LeafNavigation { get { return _leafs; } set { _leafs = value.ToList(); } }
}

And Voila, this works a treat, I can add Leafs, and update them, along with the root and EF just binds everything as normal. Add, Update and Get all work seamlessly.

I’ve uploaded this to GitHub – and I hope this helps anyone who may be having similar issues!
https://github.com/squareconnection/EFInterfaces

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s