Apache Cayenne > Index > Cayenne Examples > Copying DataMaps
Copying DataMaps
Sometimes it is useful to have a single application which can talk to the same database schemas in different databases. For example, you might have a user management application that allows you to create and update users in your system, but you want that single application to be able to support your development, testing, acceptance, and production database servers. Since the database schemas are the same (at least in theory), it would be nice to only have to define the schema once in the Cayenne Modeler and reuse it as needed. This can be done with a little bit of coding.
The Model
In the model, you'll want to create a DataDomain with a DataMap inside it. This will hold the "shared" schema. It does not need to contain a DataNode (for the database connection) since the shared information doesn't have to connect to anything. The DataMap, though, should contain all of your shared entities.
Next, you'll create additional DataDomains for each database you wish to access. In these DataDomains create a DataNode and enter the database connection information. You will not create a DataMap in these domains.
When you finish, you should have a model resembling this screenshot:

As you can see, the shared DataDomain contains a shared DataMap, but no DataNode. The non-shared (schema-specific) DataDomains contain DataNodes (for each database connection), but no DataMaps.
DataMap Shuffle
Now we need to copy the shared DataMaps into the target DataDomains for each schema. This is where a little coding needs to be done. I have a utility class called DataDomainUtilities (see below), which you can replicate or just copy the copyDataDomainDataMap() method to a convenient place for your application. When you initialize your application, you need lines of code similar to:
DataDomainUtilities.copyDataDomainDataMap("SharedDomain", "SharedDomainMap", "DevelopmentDomain"); DataDomainUtilities.copyDataDomainDataMap("SharedDomain", "SharedDomainMap", "TestingDomain"); DataDomainUtilities.copyDataDomainDataMap("SharedDomain", "SharedDomainMap", "AcceptanceDomain"); DataDomainUtilities.copyDataDomainDataMap("SharedDomain", "SharedDomainMap", "ProductionDomain");
The above needs to be done only once and will copy the shared DataMap into the given DataDomains. This will essentially replicate the schema across all of the DataDomains. If you are using Cayenne Extended Types (such as the Enumerations Example), be sure to register them before you copy the maps. That way, the extended types will also be copied with the map.
Usage
Your application can then specify which schema to use by creating a new DataContext:
DataContext dataContext = DataContext.createDataContext("AcceptanceDomain");
Any operations done in the above DataContext will be performed using the AcceptanceDomain connection settings (specified by the DataNode). You can create as many DataContexts as you like, pointing to whichever schemas/domains you want, and Cayenne will manage the connections for you.
Utility Class
Here is the utility class/method to actually copy the DataMaps to the target DataDomains.
import java.util.Collection; import java.util.Iterator; import org.objectstyle.cayenne.access.DataDomain; import org.objectstyle.cayenne.access.DataNode; import org.objectstyle.cayenne.conf.Configuration; /** * This package contains utilities for working with Cayenne DataDomains. */ public class DataDomainUtilities { /** * Copies a Cayenne DataDomain's DataMap from a source DataDomain to a target * DataDomain. Both the source and target must already exist in the Cayenne * model. This is useful when using the same map (schema is identical) across * different databases. You can define a "shared" map and then copy it to each * DataDomain required (which has it's own connection information in the DataNode). * * @param sourceDataDomainName * @param sourceDataMapName * @param targetDataDomainName */ public static void copyDataDomainDataMap(String sourceDataDomainName, String sourceDataMapName, String targetDataDomainName) { DataDomain sharedDataDomain = Configuration.getSharedConfiguration().getDomain(sourceDataDomainName); DataDomain targetDataDomain = Configuration.getSharedConfiguration().getDomain(targetDataDomainName); // Add the shared map to the target data domain targetDataDomain.addMap(sharedDataDomain.getMap(sourceDataMapName)); // Add the shared map to the data node Collection nodes = targetDataDomain.getDataNodes(); if (nodes.size() != 1) { System.out.println("Expected only one DataNode for DataDomain '" + targetDataDomainName + "' -- this DataDomain is not usable."); return; } Iterator dataNodeIterator = nodes.iterator(); // We are only getting one, though ... while (dataNodeIterator.hasNext()) { DataNode node = (DataNode) dataNodeIterator.next(); node.addDataMap(sharedDataDomain.getMap(sourceDataMapName)); } } }