Skip navigation links
Project Wonder 7.5-SNAPSHOT

Package er.extensions.partials

Partial Entities

See: Description

Package er.extensions.partials Description

Partial Entities

Latest

A review of the features of the ERXPartial implementation has been partly funded by Logic Squad. The review documents and an example/test application are available in Examples/ERXPartials directory. While not everything discussed in the review document has been completed, the example application is designed to provide a starting point for validating the features and functions of this package.

-- David Aspinall, Global Village Consulting
Sept 19, 2012

Overview

Partial Entities provide a mechanism for defining a single entity whose definition spans across multiple EOModels along with tools to interact with these partial definitions in a type-safe way.

Partial entities are specifically designed to allow reuse and extension of existing models. A very common case where this becomes useful is that of a Person entity. Person is an entity that is used in many different scenarios, each of which requires additional attributes and relationships. For instance, you may have a task management application and you want to embed your calendaring framework into it. The common Person base entity may have username and password attributes, the tasking application may add an activeTasks relationship, and the calendaring framework may add a scheduledEvents relationship as well as dayStartTime and dayEndTime attributes. Note that partials are not designed to address the issue of "roles," where different people in the system may have different roles at different times. Partial entities are designed to address the issue of combining high level modules together to form more complex static entity declarations.

Traditionally, this presents some complicated problems. How do you add these relationships onto your Person entity? Additionally, these different views of a Person technically represent the same underlying object, and ideally we want to be able to fetch these views without having to always traverse additional relationships for every view type. For instance, if CalendarPerson is a "role" of Person and stored as a separate entity (table) in the database, it would require traversing a relationship every time you need to reference calendar-specific attributes of a Person, which can be a serious performance issue if you need to show CalendarPerson attributes of multiple Person objects at time. Prefetching can alleviate some of this overhead, but semantically speaking, Person, CalendarPerson, and TaskPerson are the same entity, just as seen from different parts of your system. EOGenericRecord allows a certain amount of flexibility, but in exchange for a loss of type-safety. Java's type system does not allow mixins like Ruby, which means that you cannot just "inject" the get/set methods into the Person class and actually be able to get compile-type checking on these methods.

Design

Enter Partial Entities. With partial entities, you can declare a base Person entity, a TaskPerson partial entity that adds the activeTasks relationship, and a CalendarPerson partial entity that adds the scheduledEvents relationship and the dayStartTime and dayEndTime attributes. At runtime, the base and partial entities are merged together such that the entity named Person is the union of all of the attributes and relationships of all of its partials. In fact, the "partial entities" are not entities at all, but rather exist only as special cover classes that are generated by VelocityEOGenerator to allow compile-time type checking and get/set method access. The ability of partials to merge into a single entity means that the underlying representation in the database is such that a single row represents the union of all of the attributes of Person + CalendarPerson + TaskPerson. The makes for fairly optimal fetching behavior.

The design of the Java side of partial entities is inspired by the concept of an IAdaptable in Eclipse. Eclipse has similar problem design constraints in that it provides extension mechanisms for many types of classes in the system. Because Java lacks the concept of categories or mixins, there is no formal mechanism to extend an existing class with a compile-type-checked interface. IAdaptable in Eclipse provides a very simple interface to ask a class to adapt itself into another interface, which can consult a factory to perform that lookup. A common example of this is that you may ask a Project for its JavaProject interface, which provides additional capabilities that are specific to a JavaProject. In Partial Entities, we use the capabilities of EOF to provide the underlying flexible datastore for the entity state (that is, EOF doesn't care if we tell it that Person now has 3 new relationships and 4 new attributes as long as the underlying database definition agrees when it comes time to fetch or save). We use the IAdaptable concept to address type-safe Java interfaces to this state. Velocity EOGenerator has been extended to support the generation of special "partial entity" templates. These templates are very similar to normal EO templates except that where normal EO's extend EOGenericRecord (or ERXPartialGenericRecord in the case of partial base entities), the partials themselves extend ERXPartial, which is not a subclass of EOEnterpriseObject. It is an important concept that the partials are only a type-safe wrapper around a single EO. Person is the only EO in the above example. CalendarPerson and TaskPerson are simply type-safe "views" of Person.

Example

In code there are two ways to access the partial covers for an EO. In Java, you will want to use the programmatic interface, and in components you will want to use the binding method. The two styles look like:

Person person = ...; // fetch a Person EO from the database
CalendarPerson calendarPerson = person.partialForClass(CalendarPerson.class);
calendarPerson.setDayStartTime(new NSTimestamp());
System.out.println(calendarPerson.dayStartTime());

TaskPerson taskPerson = person.partialForClass(TaskPerson.class);
System.out.println(taskPerson.activeTasks());
or
DayStartTime : WOString {
        value = person.@CalendarPerson.dayStartTime;
        dateformat = "%m/%d/%y";
}

Usage

So how do you take advantage of partials? There are several pieces. Entities in your models need to be annotated as partials, the runtime needs to be notified of them, and Java code needs to be generated to take care of the tedium of repetitive implementation. Partial entities require the use of Project Wonder, the latest WOLips/Entity Modeler, and the latest Velocity EOGenerator (which is built into WOLips).

Model

In Entity Modeler, there is a new option under the Advanced tab of an Entity that allows the selection of a "Partial Entity". The Partial Entity is the base entity that a particular entity will augment. For instance CalendarPerson's Partial Entity is Person. Currently, a partial cannot augment another partial. For instance, TaskPerson cannot be a partial entity for CalendarPerson, rather they can only be a partial of the base Person entity.

Any attribute of the base entity can be duplicated in the partials if it makes creating relationships easier—these will just be skipped when the entities are merged at runtime. For instance, it may be easier to setup your partial's relationships if you duplicate the PK's into the partial entities.

Lastly, in your model, you should specify the class name of each partial entity. For instance, CalendarPerson may be com.mdimension.calendar.model.CalendarPerson, whereas TaskPerson might be com.mdimension.tasking.model.TaskPerson. "External name" on partial entities is currently ignored, but should be set to be the same as the base entity (for instance, CalendarPerson's external name should be Person, to imply that the CalendarPerson entity will be in the Person table).

Code Generation

Currently, only the Velocity EOGenerator in WOLips is able to generate code for partial entities. In the Defines section of your model's EOGenerator configuration, you should specify that your EOGenericRecord class should be er.extensions.partials.ERXPartialGenericRecord (rather than er.extensions.eof.ERXGenericRecord like you normally would). The Velocity templates will automatically make the superclass of partial classes er.extensions.partials.ERXPartial, but the ERXPartial partialForClass(Class) method is only on ERXPartialGenericRecord.

SQL Generation

SQL Generation with partials is a complicated subject, but ideally you should use the ERMigrations APIs to create your tables. With migrations, you can have your base framework create the generic Person table, the Calendar framework can add the appropriate columns for CalendarPerson, and the Tasking application can add the appropriate columns for tasking. If you generate SQL directly out of Entity Modeler, you will likely get multiple definitions for the same table names, which would need to be manually merged.

Runtime

To enable the use of partials at runtime, you should set the property:

er.extensions.partials.enabled=true

This will trigger the runtime system to do entity merging for you. To use the partials at runtime, refer back to the Examples section above.

Skip navigation links
Last updated: Fri, Nov 22, 2024 • 08:08 AM CET

Copyright © 2002 – 2024 Project Wonder.