~~Title: Using Master/Detail Relationships~~ Master/detail relationships are used to create relationships between tables or other datasets. The master can also be viewed as a group, whereas the detail contains the individual sets of the group. In short, master/detail is used to show the 1:n and n:m relationships of a database. == Example == Our application handles the administration of countries, states, and districts. Tables in the database are created in 3rd NF. The following is an excerpt from the HSQLDB: create table COUNTRIES ( ID INTEGER IDENTITY, COUNTRY VARCHAR(200) not null, EU CHAR(1) default 'N' not null, constraint CTRY_UK unique (COUNTRY) ) create table STATES ( ID INTEGER IDENTITY, CTRY_ID INTEGER not null, STATE VARCHAR(200) not null, constraint STAT_UK unique (STATE), constraint STAT_CTRY_ID_FK foreign key (CTRY_ID) references COUNTRIES (ID) ) create table DISTRICTS ( ID INTEGER IDENTITY, STAT_ID INTEGER not null, DISTRICT VARCHAR(200), constraint DIST_UK unique (DISTRICT), constraint DIST_STAT_ID_FK foreign key (STAT_ID) references STATES (ID) ) As the table definition shows, countries consist of individual states, and states are made up of districts. In our application, we want to create a form that allows the editing of countries, states and districts, as well as the relationships between them. We first create our server objects: /** * Returns the countries storage. * * @return the Countries storage * @throws Exception if the initialization throws an error */ public DBStorage getCountries() throws Exception { DBStorage dbsCountries = (DBStorage)get("countries"); if (dbsCountries == null) { dbsCountries = new DBStorage(); dbsCountries.setDBAccess(getDBAccess()); dbsCountries.setFromClause("V_COUNTRIES"); dbsCountries.setWritebackTable("COUNTRIES"); dbsCountries.open(); put("countries", dbsCountries); } return dbsCountries; } /** * Returns the districts storage. * * @return the Districts storage * @throws Exception if the initialization throws an error */ public DBStorage getDistricts() throws Exception { DBStorage dbsDistricts = (DBStorage)get("districts"); if (dbsDistricts == null) { dbsDistricts = new DBStorage(); dbsDistricts.setDBAccess(getDBAccess()); dbsDistricts.setFromClause("V_DISTRICTS"); dbsDistricts.setWritebackTable("DISTRICTS"); dbsDistricts.open(); put("districts", dbsDistricts); } return dbsDistricts; } /** * Returns the states storage. * * @return the States storage * @throws Exception if the initialization throws an error */ public DBStorage getStates() throws Exception { DBStorage dbsCountries = (DBStorage)get("states"); if (dbsCountries == null) { dbsCountries = new DBStorage(); dbsCountries.setDBAccess(getDBAccess()); dbsCountries.setFromClause("V_STATES"); dbsCountries.setWritebackTable("STATES"); dbsCountries.open(); put("states", dbsCountries); } return dbsCountries; } The view definition for processing the data: CREATE VIEW V_COUNTRIES AS select c.ID ,c.COUNTRY ,c.EU from COUNTRIES c order by c.COUNTRY CREATE VIEW V_STATES AS select s.ID ,s.CTRY_ID ,s.STATE from STATES s order by s.STATE CREATE VIEW V_DISTRICTS AS select d.ID ,d.STAT_ID ,d.DISTRICT from DISTRICTS d order by d.DISTRICT We now have to create the connection to the server objects and define the master/detail relationships: rdbCountries.setDataSource(dataSource); rdbCountries.setName("countries"); rdbCountries.open(); rdbStates.setDataSource(dataSource); rdbStates.setName("states"); rdbStates.setMasterReference(new ReferenceDefinition(new String[] {"CTRY_ID"}, rdbCountries, new String[] {"ID"})); rdbStates.open(); rdbDistricts.setDataSource(dataSource); rdbDistricts.setName("districts"); rdbDistricts.setMasterReference(new ReferenceDefinition(new String[] {"STAT_ID"}, rdbStates, new String[] {"ID"})); rdbDistricts.open(); A master/detail relationship can be created as follows: rdbDistricts.setMasterReference(new ReferenceDefinition(new String[] {"STAT_ID"}, rdbStates, new String[] {"ID"})); The master/detail relationship between countries and states is created via the foreign key (STATES.CTRY_ID) to the primary key (COUNTRIES.ID). This means that when a country is selected, all associated states are displayed. States that are not assigned to the selected “master” country are not shown. When a new state is entered, the correct foreign key is used automatically. The state is, therefore, assigned to the correct country. The master/detail relationship between districts and states is created between the foreign key (DISTRICTS.STAT_ID) and the primary key (STATES.ID). This means that when a state is selected, all associated districts are displayed. Districts that are not assigned to the selected “master” state are not shown. When a new district is entered, the correct state is used. The district is, therefore, automatically assigned to the correct state. \\ **Note** A master/detail relationship does NOT require that a foreign key relationship exist between two tables. Any columns can be used.