Composite Key/Id Mapping with NHibernate

nfplee picture nfplee · Aug 9, 2010 · Viewed 27.4k times · Source

I have the following tables in my database:

Announcements:
- AnnouncementID (PK)
- Title

AnouncementsRead (composite PK on AnnouncementID and UserID):
- AnnouncementID (PK)
- UserID (PK)
- DateRead

Users:
- UserID (PK)
- UserName

Usually I'd map the "AnnouncementsRead" using a many-to-many relationship but this table also has an additional "DateRead" field.

So far I have defined the following entities:

    public class Announcement
    {
        public virtual int AnnouncementID { get; set; }
        public virtual string Title { get; set; }
        public virtual IList<AnnouncementRead> AnnouncementsRead { get; private set; }

        public Announcement()
        {
            AnnouncementsRead = new List<AnnouncementRead>();
        }
    }

    public class AnnouncementRead
    {
        public virtual Announcement Announcement { get; set; }
        public virtual User User { get; set; }
        public virtual DateTime DateRead { get; set; }
    }

    public class User
    {
        public virtual int UserID { get; set; }
        public virtual string UserName { get; set; }
        public virtual IList<AnnouncementRead> AnnouncementsRead { get; private set; }

        public User()
        {
            AnnouncementsRead = new List<AnnouncementRead>();
        }
 }

With the following mappings:

public class AnnouncementMap : ClassMap<Announcement>
{
    public AnnouncementMap()
    {
        Table("Announcements");
        Id(x => x.AnnouncementID);
        Map(x => x.Title);
        HasMany(x => x.AnnouncementsRead)
            .Cascade.All();
    }
}

public class AnnouncementReadMap : ClassMap<AnnouncementRead>
{
    public AnnouncementReadMap()
    {
        Table("AnnouncementsRead");
        CompositeId()
            .KeyReference(x => x.Announcement, "AnnouncementID")
            .KeyReference(x => x.User, "UserID");
        Map(x => x.DateRead);
    }
}

public class UserMap : ClassMap<User>
{
    public UserMap()
    {
        Table("Users");
        Id(x => x.UserID);
        Map(x => x.UserName);
        HasMany(x => x.AnnouncementsRead)
            .Cascade.All();
    }
}

However when I run this I receive the following error:

"composite-id class must override Equals(): Entities.AnnouncementRead"

I'd appreciate it if someone could point me in the right direction. Thanks

Answer

Sly picture Sly · Aug 9, 2010

You should do just what NHibernate is telling you. AnnouncementRead should override Equals and GetHashCode methods. They should be based on fields that are part of primary key