1

I'm pretty new to entity framework and not an expert on database architecture, so I'm struggling to know what terms to Google for the question I have.

Say I have various entities, like Joke, Image, Story, Cartoon. They all have different data, but they share the fact that they all have an Id. In my case, a Guid.

I want to have an entity called Comment which just stores the comment, the user who made the comment, and the Id of the item commented on - which can be any of the types above. I don't want to have to create a JokeComments table, ImageComments, StoryComments etc. - because that seems inefficient - having to maintain many classes for every 'commentable' item, and means that I can't easily just grab all comments from a single User.

So I have something like this

public abstract class IdentifiableObject
{
    public IdentifiableObject()
    {
        Id = Guid.NewGuid();
    }

    public Guid Id { get; set; }   
}

public class Joke: IdentifiableObject
{ 
    public List<Comment> Comments {get; set;}
}

public class  Story : IdentifiableObject
{
    public List<Comment> Comments {get; set;}
}

public class Comment
{
     public Guid Id {get; set;}
     public String Comment {get; set;}
     [Key, ForeignKey ("IdentifiableObject")]
     public Guid TargetId {get; set;}
}

But this doesn't work, and I have no idea where to start Googling. I've read about using Interfaces, but I couldn't work out how that would work in this situation. Do I need to add a 'TargetType' property in the Comment class? If so, what would the type be? If I leave out any key in the Comment class, it creates a FK for every type it can be associaated with, which leaves me with the problem of knowing how to retrieve the target.

Can anyone explain to me how I would approach this requirement in EntityFramework, or just let me know what the name of what I am trying to do is, to help point me in the right direction on Google? Thanks..

Toby
  • 1,537
  • 10
  • 19

1 Answers1

1

It's not a great or direct answer to your question, but you can create a base class with the comments property, and it'll work;

public abstract class CommentedObject
{ 
    public List<Comment> Comments {get; set;}

public class Joke: CommentedObject
{ 
}

public class  Story : CommentedObject
{
}

public class Comment
{
     public Guid Id {get; set;}
     public String Comment {get; set;}
     [Key, ForeignKey ("IdentifiableObject")]
     public Guid TargetId {get; set;}
}

It's nasty, in that it involves inheritance to solve the problem, but it works.

You might want to read about the EF table per hierarchy and table per type strategies.

Steve Cooper
  • 20,542
  • 15
  • 71
  • 88
  • Thanks Steve - this is the way to go. Base class for all of the related types, with TablePerType. It looks like EF will understand that pattern. – Toby May 16 '16 at 09:02