Modeling people and organizations: Class Party
Classes for people and organizations are often modeled incorrectly in object models. These faults cause heavy implementation problems. In this posting I will analyze some legacy models, introduce class Party as generalization of people and organizations and provide some implementation details. Information here is based on my own experience, like always.
Legacy models
Pretty often we can see something like these in legacy object models. I added associations with address classes too because this way you get better picture of problems I will describe.
![]() | ![]() |
Both of these models introduce some pretty bad problems when we are going to implement these models. Major problem is that we have two classes – Person and Company – and we want to use them in same contexts. Their separation introduces additional association on the left model and one additional class with association on the right model. Let’s see one scenarios where problems occur.
Handling Person and Company as one
It is pretty common requirement. We may sell products to persons and companies, so they can be both our customers. We need simple dropdown list on order form to let sales person select customer. This is easy thing to do (although the solution looks awful to me):
SELECT
'P' + CAST(id AS varchar(8)) AS customer_id,
last_name + ', ' + first_name AS name
FROM
person
UNION
SELECT
'C' + CAST(id AS VARCHAR(8)) AS customer_id,
name
FROM
company
ORDER BY
name
This SQL contains something I don’t like. Take a look at these ID-s. These ID-s must contain something we can use when we save customer data. We have to know which table has this ID so we can ask person or company and then assign it to appropriate property of order.
- Get customer ID
- Determine customer type
- If customer is Person
- Extract ID
- Ask Person with specified ID
- Assign it to Person property of Order
- If customer is Company
- Extract ID
- Ask Company with specified ID
- Assign it to Company property of Order
- If customer is Person
- Save Order
Well… we got it done but taste of something awful is in mouth.
Generalizing people and organizations: class Party
People and organizations can be handled as parties of different deals. Ordering, buying, signing a contract – all these activities are made by different parties. We can generalize people and organizations using class named Party. You can read more about it and other related models from The Data Model Resource Book – Universal Data Models. I suggest you to buy these books because they help you a lot when you analyze or model your applications.
Here you can see class diagram where Person and Category are generalized using Party.
Class Party helps us a lot. All associations that are common for people and organizations we can define between Party and other classes. This way we can handle people and organizations as they are same.
Implementing Party, Person and Company
You maybe notices that Party has property called DisplayName. DisplayName is important design detail. Besides unique identifier we need also something to show as name when we list parties (we want to select customer from dropdown).
Database
Here is the example of tables in database that support our generalization. Tables shown here are simple and give you the point how to do it.
Table party is joined to other tables using one-to-one relationship. Party defines the value of primary key, other tables just use it.
We can also see that display name is field of table party. Why? I have found it very convenient if we can see the name of party when we need to manage data in tables manually. DBA is able to solve different issues faster when he or she has all the information that describes rows in table.
Of course, not using the display name in database level is also allowed. Just make your decision considering your current context and needs.
Code
On the code level we have to do some tricks. We define DisplayName as abstract property in Party. Person and Company both have override for this property. Setter of overridden properties is empty because we don’t want to let users change DisplayName manually.
public abstract class Party
{
public virtual int Id { get; set; }
public abstract string DisplayName { get; internal set; }
}
public class Person : Party
{
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public override string DisplayName
{
get
{
return LastName + ", " + FirstName;
}
internal set { }
}
}
public class Company : Party
{
public virtual string Name { get; set; }
public override string DisplayName
{
get
{
return Name;
}
internal set { }
}
}
Now we have successfully implemented basic structure of people and organizations in our code. I have used the same solution actively over past couple of years and I am pretty happy with it.