Relatude Help

The five shapes

// 1. Symmetric one-to-one: twin venues. Both ends are the same property.
public class PairedWith : OneOne<IVenue> {
    public class Pair : One { }
}

// 2. Directional one-to-one: an organizer's primary contact.
public class PrimaryContact : OneToOne<IOrganizer, IAttendee> {
    public class Organizer : OneFrom { }   // on IAttendee
    public class Contact   : OneTo { }     // on IOrganizer
}

// 3. Directional one-to-many: the workhorse.
public class EventsAtVenue : OneToMany<IVenue, IEvent> {
    public class Venue  : One { }     // on IEvent: its one venue
    public class Events : Many { }    // on IVenue: its many events
}

// 4. Symmetric many-to-many: friends.
public class Friends : ManyMany<IAttendee> {
    public class Peers : Many { }
}

// 5. Directional many-to-many: events and their attendees.
public class Attendance : ManyToMany<IEvent, IAttendee> {
    public class Events    : ManyFrom { }   // on IAttendee
    public class Attendees : ManyTo { }     // on IEvent
}
Base class Symmetry Cardinality Nested classes
OneOne<T> symmetric 1↔1, same type One
OneToOne<TFrom, TTo> directional 1↔1 OneFrom, OneTo
OneToMany<TOne, TMany> directional 1↔N One, Many
ManyMany<T> symmetric N↔N, same type Many
ManyToMany<TFrom, TTo> directional N↔N ManyFrom, ManyTo

There is no zero-or-one and no separate many-to-one: use OneToMany from the other end. When the edge itself carries data, such as a ticket price or a role, make the edge a node type with a relation to each side.