2

My app has Posts and Flags. Both of these have Responses, which have Comments.

Post
   Response
      Comment
Flag
   Response
      Comment

I'm trying to model this in EF as simply and properly as possible, but I'm not sure if I'm going overboard here with inheritance. This is what I have:

public class Post {
    [Key]
    [Required]
    public int PostId { get; set; }
    public virtual ICollection<PostResponse> Responses { get; private set; }
}

public class Flag {
    [Key]
    [Required]
    public int FlagId { get; set; }
    public virtual ICollection<FlagResponse> Responses { get; private set; }
}

I wanted to use just generic Response here, but then my Response class would need to account for both a parent Flag and Post. Adding both ParentPostId and ParentFlagId to the same class seemed like a dirty way to handle it, especially taking the relationships mapping into account. So I split Responses up:

High level Message:

// Comments, Posts, Responses all have these properties
public abstract class Message {
    [Required]
    public int PosterId { get; set; }
    public virtual User Poster { get; set; }
    public string RawContent { get; set; }            
}

Responses:

public abstract class Response : Message {
    [Key]
    [Required]
    public int ResponseId { get; set; }
    public virtual ICollection<Comment> Comments { get; set; } 
}
// will be used by Posts only
public class PostResponse : Response {
    [Required]
    public int ParentPostId { get; set; }
    public virtual Post Post { get; set; }
}
// will be used by Flags only
public class FlagResponse : Response {
    [Required]
    public int ParentFlagId { get; set; }
    public virtual Flag Flag { get; set; }
}

So see, then I had to account for the difference in Comments:

Comments:

public abstract class Comment : Message {
    [Key]
    [Required]
    public int CommentId { get; set; }
}
// will be used by PostResponses only
public class PostComment : Comment {
    [Required]
    public int ResponseId { get; set; }
    public virtual PostResponse Response { get; set; }
}
// will be used by FlagResponses only
public class FlagComment : Comment {
    [Required]
    public int ResponseId { get; set; }
    public virtual PostResponse Response { get; set; }
}

So I've fattened up my schema and now my FluentAPI codefirst configurations are going to get tricky, but my logic can now easily distinguish between types and the data is normalized.

It feels less smelly than packing everything into a single model, but I'm not sure if this is even close to a best practice, especially with performance concerns. Performance is the highest priority with the design.

Update

After spending nearly the entire afternoon on trying to implement TPH inheritance with Code-First, I've thrown my hands up. See this question:

EF Inheritance and Foreign Keys

So I think the cheapest and post performant solution would be for me to add optional FK Ids to the Response object - one for FlagId and the other for PostId. Beef up my validation a bit, be the opposite of normalized, but stay away from complicating my schema and introducing more joins for queries in TPC or TPT, and avoid the hating-myself that comes with TPH in this scenario. I think what I'm doing is brute-force TPH anyways.

I'll keep this up in case anyone has any suggestions or in case this can spare anyone else from the anguish I've experienced today.

Community
  • 1
  • 1
RobVious
  • 12,685
  • 25
  • 99
  • 181

0 Answers0