views:

195

answers:

2

My application is a multi-user podcast aggregator, using NHibernate 2.1 (and .NET 4.0 if that changes anything). I'm also a complete NHibernate n00b.

Details of each podcast are only stored once, and Users subscribe to podcasts, so there is a many-to-many mapping between podcasts and users which I have mapped in my database with a Subscriptions table:

Subscriptions(UserId, FeedId)

I also have a UserFeedItems table which stores per-user-per-item information:

UserFeedItems(UserId, FeedItemId, IsNew, ListenCount, etc.)

My object model is a bit different:

class Podcast {
    IList<PodcastFeedItem> FeedItems { get; set; }
    bool HasNew {
        get {
            // return true if any of the FeedItems are new
        }
    }
}

class PodcastFeedItem {
    bool IsNew { get; set; }
}

class User {
    IList<PodcastFeed> Subscriptions { get; set; }
}

What mappings do I need in NHibernate to correctly map the relational model to the object model? Have I gone to far by defining those "link" tables listed above? Ordering may be important here, as obviously I need to keep the feeds organised in descending chronological order.

I've read through the documentation on collection mapping, but I'm struggling to fit the examples to my own scenario.

+1  A: 

You don't need the lookup table. The answer to this question provides the details on how to perform a many to many in NHibernate

lomaxx
Thanks for your answer. The answer you link to implies I don't need a class for my lookup table (which I don't have, and wasn't expecting to need). However, the example mapping in the other answer (from the OP) still uses the lookup table. Is that right?
alastairs
Correct, you don't need to define the class, but you still need to map the relationship through the table in the database
lomaxx
+1  A: 

Its a classic Many-to-Many where a Podcast can have many subscribers and a subscriber can subscribe to many podcasts. You map it like this:

<class name="App.Core.Domain.User, App.Core" table="users">
    <set name="SubscribedPodcasts" table="subscriptions" inverse="false" cascade="all">
      <key column="userid"/>
      <many-to-many class="App.Core.Domain.Podcasts, App.Core" column="podcastid"/>
    </set>
</class>


<class name="App.Core.Domain.Podcast, App.Core" table="podcasts">
    <set name="SubscribedUsers" table="subscriptions" inverse="false" cascade="all">
      <key column="podcastid"/>
      <many-to-many class="App.Core.Domain.User, App.Core" column="userid"/>
    </set>
</class>

If you really want to store the index in the database rather than having NH order the results (I have never had to do this as its better to order by a column and have NH provide your indexes). then add

<index-many-to-many
        column="column_name"                
        class="ClassName"                   
/>

To the mapping

reach4thelasers
Thanks for the more detailed answer; unfortunately I'm still waiting for a spare moment to test this out.
alastairs
A couple of questions: 1. Why a set over a bag? 2. Should the class name be the same in both the many-to-many tags? Not one Podcasts, one Users? (I'm not sure which way around it should be, if so).
alastairs
There is an error in the above mapping, the second many-to-many shoud be class Users - sorry about that I will update the answer.
reach4thelasers
Re:Set/bag....In the .NET collections hierarchy there isn't a set implementation, so .NET users tend not to use it. NHibernate comes with an implementation of a Set from Iesi.Collections. The key thing to know about a Set is that each object can only exist once, however in a bag, e.g. IList the same object can exist more than once. For a more detailed description see:http://blogs.hibernatingrhinos.com/nhibernate/archive/2008/06/12/mapping-collections-in-nhibernate-part-1.aspxand you'll see that in theoretical terms, a set is actually the correct Collection type to use in this instance.
reach4thelasers
In practical terms though, .Net users tend to overuse bags/Lists for everything and, as long as you check the collection beforehand to ensure that the item doesn't actually exist its ok. With a Set, you can call Add() without checking and the object will be added if it doesn't exist and will be added if it does.
reach4thelasers