Hi,

I am currently trying to evaluate DataObjects.Net for a new commercial product. I am impressed with what I have read so far but Ii have a particular problem and I was wondering what your (more experienced) opinion would be regarding modelling this particular problem using DataObjects.NET.

I need to know how I would efficiently model a relational database whereby I have a field in an "Event" table which defines a "SportType"? This "SportsType" field can hold a link to different sports tables E.g. "FootballEvent", "RubgyEvent", "CricketEvent" and "F1 Event". Each of these Sports tables have different fields specific to that sport.

My goal is to be able to generically add sports types in the future as required, yet hold sport specific event data (fields) as part of my Event Entity. Is it possible to use an ORM such as DataObjects.Net to reflect such a relationship / generate the database?

I have thrown together a quick C# example to express my intent at a higher level - Please refer to the following Stack Overflow Question for examples regarding my intent: http://stackoverflow.com/questions/2546066/modeling-a-generic-relationship-expressed-in-c-in-a-database

Thanks in adavance!

This thread was imported from our support forum. The original discussion may contain more detailed answer. Original topic by holsee.

asked Mar 31 '10 at 15:21

Editor's gravatar image

Editor
46156156157


One Answer:

Your example converted to DO4 must look as follows:

// I'd add this type - adding an abstract base makes design more clean + allows you to share
// the behavior among all the descendants
[Serializable]
[HierarchyRoot]
public abstract class EventBase : Entity 
{
  [Key]
  Guid Id { get; private set; } // Or some other type
}

[Serializable]
public class Event<T> : EventBase
    where T : IEntity, new() // IEntity indicates DO4 must try  to map its descendants automatically
    // Although I'd put some stronger requirement, e.g. by using IEventData instead of IEntity here
{
    public T Data { get; set; }

    public Event(T data)
    {
        Data = data;
    }
}

[Serializable]
[HierarchyRoot]
public class FootballEvent
{
    // You need [Key]  here
    public Team CompetitorA { get; set; }  
    public Team CompetitorB { get; set; }    
}

[Serializable]
[HierarchyRoot]
public class TennisEvent
{
    // You need [Key]  here
    public Player CompetitorA { get; set; }
    public Player CompetitorB { get; set; }
}

[Serializable]
[HierarchyRoot]
public class F1RacingEvent
{
    // You need [Key]  here
    public EntitySet<Player> Drivers { get; private set; }
    public EntitySet<Team> Teams { get; private set; }
}

[Serializable]
[HierarchyRoot]
public class Team
{
    // You need [Key]  here
    public EntitySet<Player> Squad { get; set; }
}

[Serializable]
[HierarchyRoot]
public class Player
{
    public string Name { get; set; }
    public DateTime DOB { get; set; }
}

In this case Event<t> instances will be available (= mapped automatically) for all suitable Ts from model. E.g. in this case they'll be:

  • EventBase // Yes, even it, coz it's suitable

  • FootballEvent

  • TennisEvent

  • F1RacingEvent

  • Team

  • Player

If you'd like to restrict this to just certain types, you must do the following:

  • Add an interface inherited from IEntity all these types will support, e.g. IEventData.

  • Use it as generic parameter constraint for generic parameter T in Event<t>.


One more note: if you'll add a descendant of e.g. FootballEvent called SpecialFootballEvent, you won't get Event<specialfootballevent> available: DO4 maps only the most generic types in each hierarchy (so if it's possible to map just a root, only it will be mapped). In hierarchy of FootballEvent such a generic type is FootballEvent, so DO4 will map a generic instance of Event<t> just for it.

This is logical, because:

  • Each hierarchy share the same Key structure

  • So any reference of type FootballEvent is allowed to point to SpecialFootballEvent instance as well (i.e. there is a default OO logic without any restrictions)

  • Thus it's enough to map just Event<footballevent> : its Data member will be able to point to SpecialFootballEvent as well, although to deal with SpecialFootballEvent, you must cast it.

  • We actually can map Event<specialfootballevent> as well, but this isn't good from another point: you're getting an alternative allowing you to use both Event<footballevent> and Event<specialfootballevent> to reference to the same SpecialFootballEvent object. Such options are generally not good.

  • One more important reason for not having Event<specialfootballevent> is that this type will allocate an additional table (or an additional column(s) in table mapped to Event<footballevent>). But imagine inheritance hierarchy is deep: in fact, we're wasting the space for each of such, although there are no real necessity for this.

answered Apr 01 '10 at 02:25

Alex%20Yakunin's gravatar image

Alex Yakunin
29714412

Your answer
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!
toggle preview

powered by OSQA