Question

My application has a very simple model right now and I'm trying to find the best way to traverse through an aggregate. As you can see in my model diagram at the bottom, I have an account, a trip and a list of people attending a trip. I would like to be able to view all of the trips an account is apart of and I have come up with something like this:

    public List<Trip> GetAllTripsFor(int accountid)
    {
        var tripRepository = new TripRepository();
        var trips = tripRepository.FindAll();
        var userTrips = new List<Trip>();

        foreach (Trip trip in trips)
        {
            foreach (TripPeople person in trip.People)
            {
                // If this trip's person list contains this accountid
                // then add this trip to the userTrips list.
                if(person.Account.Id == accountid)
                    userTrips.Add(trip);
            }
        }

        return userTrips;
    }

To me this doesn't seem very efficient and that I'm not thinking about things correctly. Do any of you have ideas on a better way of implementing this? Perhaps I'm thinking about my model wrong? Thanks

alt text

Was it helpful?

Solution 2

thanks for your help. I think I figured out last night what I was trying to achieve. I'm not totally sure it's the best way but it is working good so far. I was able to come up with an interface like the following:

//Return a list of trips for the user
var user = accountRepository.GetUserBy(123);
var userTrips = user.Trips;

//Return all of the users attending a trip
var peopleAttendingTrip = tripRepository.GetTripBy(234).People;

//Check user's status for a trip. A user must pay some kind of deposit
//before they are considered active.
var userStatus = userTrips.SingleOrDefault().GetStatusFor(user);

To achieve this I created a many-to-many table that holds the the primary keys from User and Trip and then mapped the relationship in NHibernate to the User Class and Trip Class. Also to achieve the user's status for a trip, I created an Entity that stores the user's state along with the trip and user info. That's a little duplication of data it seems like but I like the way it currently works and looks.

If you guys have any comments or a better way to implement this let me know. I'm always up for improving something! Thanks again

alt text

OTHER TIPS

Im not supprised this doesn't feel right to you, it not. Infact it's so wrong it hurts!But instead of just just giving you grief ill explain all the reason why this is wrong@

Firstly, your load in ALL the trips into memory from the database, this essentially means you are querying a data store to get a whole load of data that you don't need and then passing it down the wire. This is fine if you have a few trips, but this will not scale at all.

Next you are recursing through each trip and calling the property "trip.People". This will then hit the database again and load ALL the data for people on EACH one of these trips. Again, this will kill you if you have several trips with several attendees. Now, this is assuming that you have no filters on your mappings or you have specifically asked NHibernate not to lazy load your People collection, but either way that's a whole load of data you don't want.

My advice would be to look at the NHibernate documents concerning querying your object model using either HQL or Linq-To-NHibernate, and you'll end up with queries that look something like the following:

HQL (MY HQL Sucks so this could be very wrong):

var hql = @"from Trip as t join t.People as p with p.Account.Id = :accountId select t"

Edit:

Actually, my brain is a little slow right now as its late, but I just realized that your doing things a little backwards here. What your actually after is all the trips that an person has been on, so why doesn't your account object have a Trips collection mapped to is? You should essentially be aiming for something like this:

var trips = accountRepo.GetAccount(123).Trips;

Edit:

Again I am tired so this may be nonsense, but I think the mapping you are looking for will look like this:

    <bag name="Trip"  cascade="all" table="TripToAccount" lazy="true">
        <key column="AccountId" />
        <many-to-many class="Trip">
            <column name="TripId" not-null="true"/>
        </many-to-many>
    </bag>

Edit:

Damn it, i should go to bed. Now I see you already have a mapping between the people and their trips so why not:

var query = "from TripPeople as tp Where tp.Account.Id = :accountId AND tp.IsActive = true select tp.Trip"

Going to stop answering now, before I do more stupid things.

What Owen said could be the best way to do it if you didn't load your trips before you hit this method.

What I suggest would be to build some kind of compare() method for a class List of trips

public class Trips: List< Trip > {

public Trips()
{
    //
    // TODO :
    //
}


#region methods

/// <summary>
/// return trip
/// </summary>

public Trip FindTrip(int accountId)
{
    return this.Find(delegate(trip t) {
    return t.AccountId == accountId; });
}
#end region 

}

I can't be sure if it's the best but that's the way I do it hahan hahan it's like the Find() method of the object class

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top