views:

25

answers:

0

Hello all,

I have the following (simplified) mappings:

public class RosterMap : ClassMap<Roster>
{
    public RosterMap()
    {
        References(tr => tr.Team)
            .Not.Nullable();

        HasMany(r => r.Players)
            .Inverse()
            .Cascade.AllDeleteOrphan();

        References(roster => roster.Match)
            .Nullable();
    }
}

public class TeamMap : ClassMap<Team>
{
    public TeamMap()
    {
        HasMany(t => t.Rosters)
            .Inverse()
            .Cascade.AllDeleteOrphan();

        HasMany(t => t.MatchesAtHome);

        HasMany(t => t.MatchesOnRoad);
    }
}

public class MatchMap : ClassMap<Match>
{
    public MatchMap()
    {
        References(m => m.HomeTeam)
            .Cascade.All()
            .Not.Nullable();

        References(m => m.RoadTeam)
            .Cascade.All()
            .Not.Nullable();

        References(m => m.HomeRoster)
            .Cascade.All();

        References(m => m.RoadRoster)
            .Cascade.All();
    }
}

I wrote a unit test to check I can successfully save a match in the database:

using (var session = Kernel.Get<ISession>())
{
    var p1 = new Player("P1", "P1", 5);
    session.Save(p1);

    var p2 = new Player("P2", "P2", 5);
    session.Save(p2);

    Team homeTeam = new Team("Home", Sex.Male);

    session.Save(homeTeam);

    homeTeam.DefaultRoster.AddPlayer(p1);

    foreach (var pit in homeTeam.DefaultRoster.Players)
        session.Save(pit);

    session.Save(homeTeam.DefaultRoster);

    Team roadTeam = new Team("Road", Sex.Male);

    session.Save(roadTeam);
    roadTeam.DefaultRoster.AddPlayer(p2);

    foreach (var pit in roadTeam.DefaultRoster.Players)
        session.Save(pit);

    session.Save(roadTeam.DefaultRoster); 

    session.Flush();

    var match = new Match
                {
                    Name = "Fuu",
                    Date = DateTime.Now,
                    Location = "Here",
                    HomeTeam = homeTeam,
                    RoadTeam = roadTeam
                };

    match.HomeRoster.UpdatePlayers(homeTeam.DefaultRoster.Players.Select(pit => pit.Player));
    match.RoadRoster.UpdatePlayers(roadTeam.DefaultRoster.Players.Select(pit => pit.Player));

    session.Save(match);
    session.Flush();
}

This works, and generates the following SQL:

NHibernate: INSERT INTO Players (Sex, FirstName, LastName, DefaultNumber, Visible, DefaultPosition_id, Id) VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6);@p0 = 0 [Type: Int32 (0)], @p1 = 'P1' [Type: String (0)], @p2 = 'P1' [Type: String (0)], @p3 = 5 [Type: Int32 (0)], @p4 = True [Type: Boolean (0)], @p5 = NULL [Type: Int32 (0)], @p6 = 1 [Type: Int32 (0)]
NHibernate: INSERT INTO Players (Sex, FirstName, LastName, DefaultNumber, Visible, DefaultPosition_id, Id) VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6);@p0 = 0 [Type: Int32 (0)], @p1 = 'P2' [Type: String (0)], @p2 = 'P2' [Type: String (0)], @p3 = 5 [Type: Int32 (0)], @p4 = True [Type: Boolean (0)], @p5 = NULL [Type: Int32 (0)], @p6 = 2 [Type: Int32 (0)]
NHibernate: INSERT INTO Teams (Sex, Name, Visible, Location, Id) VALUES (@p0, @p1, @p2, @p3, @p4);@p0 = 0 [Type: Int32 (0)], @p1 = 'Home' [Type: String (0)], @p2 = True [Type: Boolean (0)], @p3 = '' [Type: String (0)], @p4 = 1 [Type: Int32 (0)]
NHibernate: INSERT INTO "Roster" (Team_id, Match_id, Id) VALUES (@p0, @p1, @p2);@p0 = 1 [Type: Int32 (0)], @p1 = NULL [Type: Int32 (0)], @p2 = 1 [Type: Int32 (0)]
NHibernate: INSERT INTO "PlayerInTeam" (PlayerNumber, Player_id, Position_id, Roster_id, Id) VALUES (@p0, @p1, @p2, @p3, @p4);@p0 = 5 [Type: Int32 (0)], @p1 = 1 [Type: Int32 (0)], @p2 = NULL [Type: Int32 (0)], @p3 = 1 [Type: Int32 (0)], @p4 = 1 [Type: Int32 (0)]
NHibernate: INSERT INTO Teams (Sex, Name, Visible, Location, Id) VALUES (@p0, @p1, @p2, @p3, @p4);@p0 = 0 [Type: Int32 (0)], @p1 = 'Road' [Type: String (0)], @p2 = True [Type: Boolean (0)], @p3 = '' [Type: String (0)], @p4 = 2 [Type: Int32 (0)]
NHibernate: INSERT INTO "Roster" (Team_id, Match_id, Id) VALUES (@p0, @p1, @p2);@p0 = 2 [Type: Int32 (0)], @p1 = NULL [Type: Int32 (0)], @p2 = 2 [Type: Int32 (0)]
NHibernate: INSERT INTO "PlayerInTeam" (PlayerNumber, Player_id, Position_id, Roster_id, Id) VALUES (@p0, @p1, @p2, @p3, @p4);@p0 = 5 [Type: Int32 (0)], @p1 = 2 [Type: Int32 (0)], @p2 = NULL [Type: Int32 (0)], @p3 = 2 [Type: Int32 (0)], @p4 = 2 [Type: Int32 (0)]
NHibernate: INSERT INTO "Roster" (Team_id, Match_id, Id) VALUES (@p0, @p1, @p2);@p0 = 1 [Type: Int32 (0)], @p1 = NULL [Type: Int32 (0)], @p2 = 3 [Type: Int32 (0)]
NHibernate: INSERT INTO "PlayerInTeam" (PlayerNumber, Player_id, Position_id, Roster_id, Id) VALUES (@p0, @p1, @p2, @p3, @p4);@p0 = 5 [Type: Int32 (0)], @p1 = 1 [Type: Int32 (0)], @p2 = NULL [Type: Int32 (0)], @p3 = 3 [Type: Int32 (0)], @p4 = 3 [Type: Int32 (0)]
NHibernate: INSERT INTO "Roster" (Team_id, Match_id, Id) VALUES (@p0, @p1, @p2);@p0 = 2 [Type: Int32 (0)], @p1 = NULL [Type: Int32 (0)], @p2 = 4 [Type: Int32 (0)]
NHibernate: INSERT INTO "PlayerInTeam" (PlayerNumber, Player_id, Position_id, Roster_id, Id) VALUES (@p0, @p1, @p2, @p3, @p4);@p0 = 5 [Type: Int32 (0)], @p1 = 2 [Type: Int32 (0)], @p2 = NULL [Type: Int32 (0)], @p3 = 4 [Type: Int32 (0)], @p4 = 4 [Type: Int32 (0)]
NHibernate: INSERT INTO Matches (Name, Date, Location, Championship_id, HomeTeam_id, RoadTeam_id, HomeRoster_id, RoadRoster_id, Id) VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8);@p0 = 'Fuu' [Type: String (0)], @p1 = 8/10/2010 17:24:18 [Type: DateTime (0)], @p2 = 'Here' [Type: String (0)], @p3 = NULL [Type: Int32 (0)], @p4 = 1 [Type: Int32 (0)], @p5 = 2 [Type: Int32 (0)], @p6 = 3 [Type: Int32 (0)], @p7 = 4 [Type: Int32 (0)], @p8 = 1 [Type: Int32 (0)]
NHibernate: UPDATE "Roster" SET Team_id = @p0, Match_id = @p1 WHERE Id = @p2;@p0 = 1 [Type: Int32 (0)], @p1 = 1 [Type: Int32 (0)], @p2 = 3 [Type: Int32 (0)]
NHibernate: UPDATE "Roster" SET Team_id = @p0, Match_id = @p1 WHERE Id = @p2;@p0 = 2 [Type: Int32 (0)], @p1 = 1 [Type: Int32 (0)], @p2 = 4 [Type: Int32 (0)]

Now, I'd like 2 things:

  1. Set in the MatchMap, that HomeRoster and RoadRoster can't be null
  2. Avoid that, at the end of the SQL, the insertions of the match rosters, and after the match is inserted, an update of the rosters, and replace this by 3 single INSERT.

For #2, I don't know how to do, since there aren't any HasMany mappings between my entities, and then I can't set Inverse().

For #1: I've added .Not.Nullable() to the mappings for HomeRoster and TeamRoster in MatchMap, but then, I've got a ConstraintViolationException on the first call to Flush(), and once again, I really don't know why.

Any help?

Thanks in advance

Mike