locked
Table-per-hierarchy RRS feed

  • Question

  • User-1279424106 posted

    Hi forum,

    i've got two models "Post" and "Content" (a blog's post contains several contents, each of a specific type). I've used table-per-hierarchy to make the models "ContentText", "ContentImage" or "ContentCode" inherit from an abstract class "Content".

    On a post's detail-page i would like to show all contents belonging to the given post, independent from their type / concrete class. But how can i fetch them an iterate through the collection in a razor view as the objects are from different classes (ContentText, ContentImage, or ContentCode)? Or is my approach wrong at all?

    Below are my (shortened) classes.

    Kind regards, Jan

    Public Class Post
    
        <Key>
        Public Property ID As Integer
    
        <Required>
        <StringLength(60, MinimumLength:=3)>
        Public Property Title As String
    
        Public Overridable Property Contents As ICollection(Of Content)
    
    End Class
    Public MustInherit Class Content
    
        <Key>
        Public Property ID As Integer
    
        <Required>
        <StringLength(60, MinimumLength:=3)>
        Public Property Headline As String
    
        Public Overridable Property PostId As Integer?
    
        Public Overridable Property Post As Post
    
    End Class
    
    Public Class ContentText
        Inherits Content
    
        <DataType(DataType.MultilineText)>
        Public Property Text As String
    
    End Class
    
    Public Class ContentCode
        Inherits Content
    
        <DataType(DataType.MultilineText)>
        Public Property Code As String
    
    End Class
    
    Public Class ContentImage
        Inherits Content
    
        <DataType(DataType.ImageUrl)>
        Public Property Image As String
    
    End Class


    Wednesday, March 11, 2015 8:25 AM

Answers

  • User-2110585397 posted

    Hi,

    Thanks for your post.

    I think your approach is ok. If you want to fetch them in a razor view, you could try the following code:

    @foreach (var item in ViewBag.Post.Contents)
    {
        if (item is ContentText)
        {
            // do something 
        }
        else if (item is ContentImage)
        {
            // do something 
        }
        else if(item is ContentCode)
        {
            // do something
        }
    }

    Hope this can be helpful to you.

    Sherwin Zhao
    Best Regards

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, March 12, 2015 2:13 AM

All replies

  • User1689970273 posted

    Hi Jkbms,

    your model is wrong. ContentText,ContentImage, and Contentcode will not be exposed at all since they all inherit from your abstract class Content. You must create a new class that captures the abstract class content and will contain ContentText,ContentImage, and Contentcode class. After which you correct your Post class to reference the collection of your new class instead of Content class.

    In this way, you can iterate it with you views as a detail page. Hope this helps.

    Wednesday, March 11, 2015 9:49 AM
  • User-1279424106 posted

    Hi itpreneur,

    thanks for your reply. What do you mean by "that captures the abstract class content and will contain ContentText,ContentImage, and Contentcode class"?

    Creating a class "Content" which inherits from abstract class "AbstractContent". How should this class "Content" then capture the other classes?

    Kind regards, Jan

    Wednesday, March 11, 2015 11:31 AM
  • User1689970273 posted

    Does your ContentText,ContentImage, and Contentcode class represents a probable table schema or a column in a content? The reason I asked you this will depend on your answer so I can guide you how we will be able to construct and be made available for your razor view.

    Wednesday, March 11, 2015 11:52 AM
  • User-1279424106 posted

    They should represent a column in a content.

    All "Contents" (ContentText, ContentImage, ContentCode etc.) share some same properties (like "title") but all of them have their own additional properties.

    I hope you understand, don't know how to explain it better ;)

    Wednesday, March 11, 2015 12:15 PM
  • User1689970273 posted

    In this case, the following class ContentText, ContentImage, and Contentcode class should not inherit from Content class.

    Your class should look like the following

    Public Class ContentText
      
    
        <DataType(DataType.MultilineText)>
        Public Property Text As String
    
    End Class
    
    Public Class ContentCode
       
    
        <DataType(DataType.MultilineText)>
        Public Property Code As String
    
    End Class
    
    Public Class ContentImage
      
    
        <DataType(DataType.ImageUrl)>
        Public Property Image As String
    
    End Class
    Public Class Content
    
        <Key>
        Public Property ID As Integer
    
        <Required>
        <StringLength(60, MinimumLength:=3)>
        Public Property Headline As String
        Public Property ContentImage as ContentImage
    Public Property ContentText as ContentText
        Public Property ContentCode as ContentCode
    Public Overridable Property PostId As Integer? 
    Public Overridable Property Post As Post End Class

    If those three classes would result in a table instead of column basing from your answer, then you need to review again your approach. to implement TPT.

    In your case, you have only two tables  Post and Content where content includes all those 3 columns.

    Wednesday, March 11, 2015 1:00 PM
  • User-1279424106 posted

    Hmm, i'm confused. Are you sure this is the right way? I don't want to have the different types of "Content" being stored in separate properties...

    I've found the following article, which seems to be related to what i would like to realize. Imagine, "BillingDetails" represents "Content", "BankAccount" means "ContentText", and "CreditCard" means "ContentImage". It is TPH and the class structure is as in my original approach. The solution seems to be the POLYMORPHIC QUERIES:

    IQueryable<BillingDetail> linqQuery = from b in context.BillingDetails select b;
    List<BillingDetail> billingDetails = linqQuery.ToList();

    linqQuery is polymorphic and return a list of objects of the type BillingDetail, which is an abstract class but the actual concrete objects in the list are of the subtypes of BillingDetail: CreditCard and BankAccount.

    But how can the result / the polymorphic query in my case be a property of the parent object "Post"? And how can i tell razor, that the "Content" objects have subclasses?

    The article is dated from 2010... Is this still valid?

    Wednesday, March 11, 2015 6:47 PM
  • User1689970273 posted

    I think I know what you want. pardon me if this is in C# coz I'm really into C#

    using (var ctx=new PostEntities()){

       Content _content=ctx.Contents.SingleOrDefault<Content>(p=>p.postId == postid);

    if (_content !=null){

        switch(_content.GetType()){

          case typeof(ContentText):  // do something

                                               break;

            case typeof(ContentCode):  // do something                                          

                       break;

              case typeof(ContentImage):  // do something                        

                                             break;

       }

     

    }

    }

    Hope this helps.

    Wednesday, March 11, 2015 11:54 PM
  • User-2110585397 posted

    Hi,

    Thanks for your post.

    I think your approach is ok. If you want to fetch them in a razor view, you could try the following code:

    @foreach (var item in ViewBag.Post.Contents)
    {
        if (item is ContentText)
        {
            // do something 
        }
        else if (item is ContentImage)
        {
            // do something 
        }
        else if(item is ContentCode)
        {
            // do something
        }
    }

    Hope this can be helpful to you.

    Sherwin Zhao
    Best Regards

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, March 12, 2015 2:13 AM
  • User-1279424106 posted

    Great, this one looks good! I will give it a try now ;)

    Btw: Is this still good "software design"? As there is some logic in the presentation layer now... Or are there better approaches to realize this?

    Thursday, March 12, 2015 4:59 AM
  • User-1279424106 posted

    There is one addition i would like to ask you: It there any possibility in c#/vb to get the subclass name directly? Instead of "if (item is ContentText)" i would like to do something like:

    html.partial("Content" & item.getType().toString)

    But item.getType() always returns the name of the base class "Content".

    Thursday, March 12, 2015 6:26 AM