scratchyback
scratchyback

Reputation: 127

fluent nhibernate many-to-many with a following many-to-many mapping

I have a many-to-many hierarchical situation I just can't figure out how to solve mapping wise.

I have an entity Incident. This Incident can have many Events. An event is nothing but a value object so i created a many-to-many mapping which works perfectly fine.

Now comes the bit i cant figure out... Every Event selected for an Incident can have multiple Causes (which is a value object as well)

Below is the simplified datamodel (events and causes are both stored in SystemValues and have Type as their discriminatorvalue): enter image description here

(ID in table IncidentEvent is a surrogate primary key to avoid hassle with a composite key)

My mapping is as follows (simplified): Incident:

public class IncidentMap : ClassMap<Incident> {

    public IncidentMap() {
    Table("Incident");
    Id(x => x.ID).GeneratedBy.Identity();

        HasManyToMany(x => x.Event)
        .Table("IncidentEvent")
        .ParentKeyColumn("IncidentID")
        .ChildKeyColumn("EventID");
    }
}

Event (subclassmapped from a general 'SystemValueMap'):

public class EventMap : SubclassMap<StoryWhere> {
    public EventMap() {
        DiscriminatorValue((int)SystemValue.Type.Event);
        HasManyToMany(x => x.Incident)
        .Table("IncidentEvent")
        .ParentKeyColumn("IncidentID")
        .ChildKeyColumn("EventID");

        HasManyToMany(x => x.Cause)
            .Table("IncidentEventCause")
            .ParentKeyColumn("IncidentEventID")
            .ChildKeyColumn("CauseID");
    }
}

Cause:

public class CauseMap : SubclassMap<Cause> { 
    public CauseMap() { DiscriminatorValue((int)SystemValue.Type.Cause); }
}

As you can see the mapping for 'Event' is a mess and of course it doesnt work. When an insert is done, I get foreignkey contraints as NHibernate tries to insert EventID into columns IncidentEventID of table IncidentEventCause. I probably need to tell Nhibernate how to use IncidentEventID instead. I need to make the Event be aware of it's many-to-many relation with incident and of it's following relation with Cause, but I'm afraid I don't know how.

Hoping someone can point me in the right direction.

Upvotes: 3

Views: 1593

Answers (1)

Firo
Firo

Reputation: 30803

if possible you should refactor the database schema and exchange IncidentEventId with EventId in the table IncidentEventCause.

The mapping you want is not easily possible. Here a workaround where the persistence leaks into the domain.

public class IncidentMap : ClassMap<Incident>
{
    public IncidentMap()
    {
        Id(x => x.ID).GeneratedBy.Identity();

        HasManyToMany(x => x.Events)
            .Table("IncidentEvent")
            .ParentKeyColumn("IncidentID")
            .ChildKeyColumn("EventID")
            .ChildWhere("type=" + (int)SystemValue.Type.Event);
    }
}

public class Event
{
    private EventDetails Details { get; set; }
    public string Name { get { return Details.Name; } set { Details.Name = value; } }

}

class EventDetails : SystemValue
{
    public virtual string Name { get; set; }
}

public class EventMap : ClassMap<Event>
{
    public EventMap()
    {
        Table("IncidentEvent");

        Id(x => x.Id, "Id").GeneratedBy.Identity();

        References(x => x.Incident, "IncidentID");
        References(Reveal.Member<Event>("Details"), "EventID").Not.LazyLoad();

        HasManyToMany(x => x.Causes)
            .Table("IncidentEventCause")
            .ParentKeyColumn("IncidentEventID")
            .ChildKeyColumn("CauseID");
    }
}

public class EventDetailsMap : SubclassMap<EventDetails>
{
    public EventDetailsMap()
    {
        DiscriminatorValue((int)SystemValue.Type.Event);
        Map(x => x.Name);
    }
}

public class CauseMap : SubclassMap<Cause>
{
    public CauseMap()
    {
        DiscriminatorValue((int)SystemValue.Type.Cause);
        Map(x => x.Name);
    }
}

Upvotes: 2

Related Questions