views:

191

answers:

7

I'm designing an application which deals with two sets of data - Users and Areas. The data is read from files produced by a third party. I have a User class and an Area class, and the data is read into a Users array and an Areas array (or other appropriate memory structure, depending on the technology we go with).

Both classes have a unique ID member which is read from the file, and the User class contains an array of Area IDs, giving a relationship where one user is associated with many Areas.

The requirements are quite straightforward:

  • List of Users
  • List of Areas
  • List of Users for Specified Area
  • List of Areas for Specified Users

My first thought was to leave the data in the two arrays, then for each of the requirements, have a seperate method which would interrogate one or both arrays as required. This would be easy to implement, but I'm not convinced it's necessarily the best way.

Then I thought about having a 'Get Areas' method on the User class and a 'Get Users' member on the Area class which would be more useful if for example I'm at a stage where I have an Area object, I could find it's users by a property, but then how would a 'Get Users' method on the Area class be aware of/have access to the Users array.

I've had this problem a number of times before, but never really came up with a definitive solution. Maybe I'm just making it more complicated than it actually is. Can anyone provide any tips, URLs or books that would help me with this sort of design?

UPDATE: Thank you all for taking your time to leave some tips. Your comments are very much appreciated.

I agree that the root of this problem is a many-to-many relationship. I understand how that would be modelled in a relational database, that's pretty simple.

The data I receive is in the form of binary files from a third party, so I have no control over the structure of these, but I can store it whichever way is best when I read it in. It is a bit square pegs in round holes, but I thought reading it in then storing it in a database, the program would then have to query the database to get to the results. It's not a massive amount of data, so I thought it would be possible to get out what I need by storing it in memory structures.

A: 

Hi, Why not use DataTables with relations, if .NET is involved? You may want to look into Generics as well, again, if .NET is involved.

Saif Khan
If I was using .NET, I would use generic lists instead of arrays. I don't really have much experience of working with DataTables however. I shall look into that.
Gavin
+7  A: 

this is really a many-to-many relationship,

User <<--->> Area

break it up into 3 objects, User, Area, and UserArea:

User: Id, name, etc.
Area: Id, name, etc.
UserArea: UserId, AreaId
Steven A. Lowe
+2  A: 

Does an area belong to multiple users? If yes, it's a technically a many-to-many relationship. If you were to transform the data into a relational database, you'd create a table with all the relationships. I guess if you want to work with arrays, you could create a third array. Or if you actually want to do this in an OO way, both classes should have arrays of pointers to the associated areas/users.

MattW.
This is the sort of thing I was thinking, but wasn't really sure about. In terms of the pointers, I'd have to read one array (or generic list or whatever), read the second array, then have a third method to populate the pointer arrays of each?
Gavin
A: 

One option is to use a dictionary for each of the last 2 requirements. That is, a Dictionary<Area, List<User>> and a Dictionary<User, List<Area>>. You could build these up as you read in the data. You might even wrap a class around these 2 dictionaries, and just have a method on that class for each of the requirements. That would allow you to make sure the dictionaries stay in sync.

chessguy
I think your brackets got mangled
Marcus Downing
+3  A: 

Very basic, but the idea is:

struct/class Membership
{
   int MemberID;
   int userID;
   int areaID;
}

This class implements the "user belongs to area" membership concept. Stick one of these for each membership in a collection, and query that collection for subsets that meet your requirements.

EDIT: Another option

You could store in each Member a list of Areas, and in each Area, a list of Members.

in Area:

public bool addMember(Member m)
{
   if (/*eligibility Requirements*/)
   {
      memberList.add(m);
      m.addArea(this);
      return true;
   }
   return false;
}

and a similar implementation in Member (without the callback)

The advantage of this is that it's pretty easy to return an iterator to walk through an Area and find Members (and vice versa)

The disadvantage is that it's very tightly coupled, which could cause future problems.

I think the first implementation is more LINQ friendly.

chris
Similar to the idea from Steven A. Lowe. I could do something like this, and it would look like the the sort of model I would have in a relational database, but in terms of Objects, I thought there may be a better way to allow an instance of User to know it's associated users and vice versa.
Gavin
+1  A: 

I'm sorry, but this is not an object-oriented problem. It is a relational problem. Hence all the references to cardinality (many-to-many). This is relational database modeling 101. I don't mean to criticize Gavin, just to point out a new perspective.

So what good is my rant. The answer should be to integrate with a relational data store, not to pound it into a object oriented paradigm. This is the classic square peg, round hole issue.

dacracot
A: 

Agree with dacracot

Also look at DevExpress XPO

Saif Khan