Ramblings on a functional concept in ERP software
Think about Algebraic Data Types (ADT) and how they’re basically unions. A most obvious example being a discriminated union in F#.
Wikipedia -Algebraic data type
In computer programming, especially functional programming and type theory, an algebraic data type is a kind of composite type, i.e., a type formed by combining other types.
Two common classes of algebraic types are product types (i.e., tuples and records) and sum types (i.e., tagged or disjoint unions or variant types).The values of a product type typically contain several values, called fields. All values of that type have the same combination of field types. The set of all possible values of a product type is the set-theoretic product, i.e., the Cartesian product, of the sets of all possible values of its field types.
Then think about ERP systems, such as Oracle E-business-suite. In basically every ERP system there is a concept of an entity somewhere, and this entity can be a person, a business organization, a standalone entity of some kind.
This entity is effectively a discriminated union. And then this entity has relationships to other entities, such as a person may have a “contact of” relationship with a business, signifying this person is a business contact there.
Or, more abstractly, this is often used in permission systems. To grant permissions to an abstract entity, rather than specialized permission tables for every case, and then queries to detect permissions for an organization or a person only has to join on the one entity table.
in F#, it might look something like this:
type Entity =
| Person of Person
| Organization of Organization
| Department of Department
| etc.
And in pseudo-SQL, it is often represented like this:
TABLE Entity
ID: int
TableName: string -- Organization, Department, Person, etc.
TableID: int -- The table ID of the table above.
Oracle E-Business-Suite substitutes the name “Party” for “Entity”, but it’s basically the same thing.
The IMMENSE downside is that it doesn’t have foreign keys, TableID could point to any of the three tables of Person, Organization, Department, and a custom constraint to simulate a foreign key to those 3 tables is quite slow.
An alternative is this:
TABLE Entity
ID: int
PersonID: int ForeignKey
OrganizationID: int ForeignKey
DepartmentID: int ForeignKey
Add UniqueConstraint ((DepartmentID == null and OrganizationID == null and PersonID != null)
or (DepartmentID == null and OrganizationID != null and PersonID == null)
or (DepartmentID != null and OrganizationID == null and PersonID == null))
This necessitates more schema changes anytime a new type of entity is added. But foreign keys exist, and even though foreign Keys are nice constraints and guarantees, the query speed from indexes is the big win.
Now when this table is read into memory, it’d probably go into a class like this via Entity Framework:
class databaseDTO {
public int EntityID;
public Person Person;
public Organization Organization;
public Department Department;
}
This isn’t terrible, but it sure isn’t a discriminated union however, it translates easily into a discriminated union so long as the uniqueconstraint on the DB is correct.
if(databaseDTO.Person != null) {
return Entity.Person ({
// map person fields
})
}
else if(databaseDTO.Department != null) {
return Entity.Department ({
// map department fields
})
}
else if(databaseDTO.Organization != null) {
return Entity.Organization ({
// map organization fields
})
}
And then, tada, I have my Entity
discriminated union from a generic line-of-business application in F#
Summary
I’ve seen the concept of an “Entity” or “Party” at multiple past employers, and it seems to be a very often used concept in Enterprise software.