views:

97

answers:

2

I'm beginning work on a new project that's would be much easier if there was some way to make different data models polymorphic. I'm looking at using the Entity Framework 4.0 (when it's released), but have been unable to determine if it will actually be able to work.

Here's the basic scenario. I'm implemented a comment system, and would like to be able to connect it to many different types of models. Maybe I want comments on a person's profile, and comments on a webpage. The way I would do this in the past is to create relationships between the person table and the comment table separately from the relationship between the webpage table and the comment table. I think this leads to an overly complicated table structure in the database, however.

It would be best if I could just be able to add an interface to the objects I want comments on, and then simplify the table structure in the database to a single relationship.

The problem I'm running into is that I don't seem to know the right terminology in order to find information about how to do this type of thing. Any help anyone can provide would be greatly appreciated.

+2  A: 

I accomplish this with LinqToSql and partial classes. For each class that I want to implement an interface, I go to create a non-tool-generated file that contains part of the partial class that declares the class to implement the interface.

For example:

Generated code:

// this code is generated by a tool blah blah
partial class FooComment {
    // all the generated crap
    string Author {
        // ...
    }
    // etc
}

The interface:

interface IComment{
    string Author{ get; }
    // etc
}

My code:

// lovingly hand-written by me
partial class FooComment : IComment {
}

Now, if you want to cast any group of FooComments to IComment, use the Cast linq extension method:

db.FooComments.Cast<IComment>()
recursive
Yes, this is the type of solution I was thinking of. I was hoping there might be a way to do it that would handling the type casting transparently, but a generic function is probably the best I'm going to get.
josh
+1  A: 

If you design your "comments table" to be comment-type-agnostic (just the basics, like an id, date & time, and text content), you can then use a single additional table that maps them all.

public interface ICommentable
{
   int CommentTypeCode
   int Id
   ...
}

Now that mapper table contains columns:

  • comment_type_code
  • target_object_id
  • comment_id

Your comments all go in one table, with an Id Your various "target objects" must all have an Id of the same type

Now you can arbitrarily add new "commentable" objects to your system without changing the comments table or the mapper table -- just assign it a new type code and create the table with the requisite Id column.

Jay
Yes, this is exactly the type of thing I was thinking of. I was hoping there might be a way that would handle the type-casting transparently, but it looks like I'm going to have to just bite the bullet and do it.In this case, I would have to check the target_object_id, as well as the comment_type, which will probably just be the System.Type of the target object. I haven't needed to work a lot with that, so it appears I'm going to learn.
josh
Well, this is assuming that your objective is to reduce the number of tables in your database, which I gathered from the original question.I might be inclined to instead create "mapper tables" for each comment type, but still keep all the comments in a comment table.If you have a "post_comments" table with a post_id column and a comment_id column, you can query that when your view or model needs the comments for a particular post id -- no type-casting required.
Jay
yes, that's right, to reduce the number of tables, and the amount of code that needs to be written. In a perfect world, it would work something like Ruby's mix-ins, but that's not really possible in C#. It isn't a big deal, I was just hoping I was missing something.
josh