0

I'm trying to figure out how to structure my entity mappings to achieve the following:

public class Document
{
    public virtual string Name { get; set; }
    // Other properties
    public IList<Document> RelatedDocuments { get; set; }
}

I'd like to have a relationship table that has ID pairs of the related Documents.

Right now I'm addressing this problem with the solution described in this SO question: Fluent Nhibernate mapping related items (crazy coincidence that the OP's name is the same as mine).

I'd rather have a single list of related items and not have to have one for RelatedTo and one for RelatedFrom. Is that possible?


To clarify, the problem I'm looking to solve is that if I relate Document A to Document B, I need Document A's RelatedDocuments list to have Document B in it, and Document B's RelatedDocuments list to have Document A in it, without having to create two relationships.
Community
  • 1
  • 1
Josh Anderson
  • 5,975
  • 2
  • 35
  • 48

1 Answers1

1

Try something like this:

class Document
{
    public int Id { get; set; }
    public string Name { get; set; }
    public IList<Document> Related { get; set; }

    public void RelateTo(Document other) 
    {
      this.Related.Add(other);
      other.Related.Add(this);
    }
}

class DocumentMap : FluentNHibernate.Mapping.ClassMap<Document>
{
    public DocumentMap()
    {
        Table("Documents");
        Id(x => x.Id);
        Map(x => x.Name);
        HasManyToMany(x => x.Related)
            .Table("DocumentRelations")
            .ParentKeyColumn("DocumentId")
            .ChildKeyColumn("RelatedDocumentId");
    }
}

The DocumentRelations table is the association table which specifies that RelatedDocumentId is related to DocumentId. The tables would look like:

create table Documents
(
  Id int identity primary key clustered,
  Name varchar(100)
)

create table DocumentRelations
(
 DocumentId int,
 RelatedDocumentId int,
 primary key clustered (DocumentId,RelatedDocumentId)
)

You should consider whether you need to have any data associated with the relationship itself. In that case, the related collection would be a collection of RelatedDocument instances which would have the related document as a property and the mapping would be HasMany.

eulerfx
  • 36,769
  • 7
  • 61
  • 83
  • I haven't tried this, but it appears that the suggestion would only work if I manually duplicated the relationships across all related entities. To clarify the outcome I'm looking for, if I add a relationship to DocB and DocC from DocA, I want to see DocA and DocC in DocB's related list, DocA and DocB in DocC's list, etc. – Josh Anderson Aug 29 '12 at 12:28
  • So are the relationships both [transitive](http://en.wikipedia.org/wiki/Transitive_relation) and [symmetric](http://en.wikipedia.org/wiki/Symmetric_relation)? Meaning, if A is related to B and C, then B and C are both related to A and to each other? – eulerfx Aug 29 '12 at 17:19
  • Not transitive, just symmetric. So if A is related to B and C is related to A, the list of items related to A would be B, C. – Josh Anderson Aug 29 '12 at 19:42
  • In that case you do have to duplicate the relationships. In other words, the DocumentRelations table will have to have a record for each side of the relationship. I've updated the code same to contain a RelateTo method, which will ensure both relationships are persisted. – eulerfx Aug 29 '12 at 21:03
  • That's a workable solution. I was hoping for a way to make NHibernate play with a SQL solution like this: http://stackoverflow.com/questions/474119/what-is-the-best-way-to-represent-a-many-to-many-relationship-between-records-in, but I don't think NH likes unions like that and I don't think a view would work in that scenario. – Josh Anderson Aug 29 '12 at 21:32
  • You could create a view DocumentRelationsView and have NHibernate map to that. Create a insert/update/delete trigger on the view such that it inserts both sides of the relationship into the underlying DocumentRelations table. This however will create an inconsistency in your code because right after a relation is created, it will be bi-directional in the database, but uni-directional in memory until the entities are re-hydrated. – eulerfx Aug 29 '12 at 21:42