Az összetett entitás a Java EE egyik programtervezési mintája. Célja, hogy egymással kapcsolatban álló perzisztálható objektumokat egy egységként kezeljen, szemben azzal, hogy különálló beanekben tartalmazná az adatokat és az objektumgráfot.[1]
Az összetett entitás többféleképpen is megvalósítható. A minta rendszerint tartalmaz egy összetett objektumot, egy durvaszemcsés és több finomszemcsés objektumot.[1]
Az összetett entitás objektum vagy maga a durvaszemcsés objektum, vagy referencia a durvaszemcsés objektumra.[1]
A durvaszemcsés objektum saját életciklusával kezeli kapcsolatait a többi objektumhoz. Lehet az összetett entitás által tartalmazott részobjektum, vagy az az által hivatkozott objektum, vagy pedig maga az összetett objektum.[1]
A függő objektumok életciklusát a durvaszemcsés objektum kezeli. Hivatkozhat más függő objektumokra, ezzel faszerkezetet hozva létre.[1]
Az Oracle leírása szerint segít kiküszöbölni az entitások közötti kapcsolatokat, javítja a kezelhetőséget az entitásbeanek redukálásával, javítja a hálózati áteresztőképességet, csökkenti az adatbázis sémafüggőségét, növeli az objektumszemcsézettséget, megkönnyíti az összetett átviteli objektumok létrehozását, továbbá egyszerűsíti a többszintű objektumfüggőségi gráfokat.
A legnagyobb hátránya az, hogy a perzisztenciát a beannek kell kezelnie. Ha mégis a konténerre bíznánk a perzisztenciát, akkor is sok kiegészítő kódra van szükség, ami a perzisztencia logikáját kezeli. Ez több munkát, és több hibalehetőséget jelent:
Egy Professional Service Automation alkalmazás példa kódja, ahol az erőforrás objektum összetett entitásként van megvalósítva.
package corepatterns.apps.psa.ejb;
import corepatterns.apps.psa.core.*;
import corepatterns.apps.psa.dao.*;
import java.sql.*;
import javax.sql.*;
import java.util.*;
import javax.ejb.*;
import javax.naming.*;
public class ResourceEntity implements EntityBean {
public String employeeId;
public String lastName;
public String firstName;
public String departmentId;
public String practiceGroup;
public String title;
public String grade;
public String email;
public String phone;
public String cell;
public String pager;
public String managerId;
// Collection of BlockOutTime Dependent objects
public Collection blockoutTimes;
// Collection of SkillSet Dependent objects
public Collection skillSets;
...
private EntityContext context;
// Entity Bean methods implementation
public String ejbCreate(ResourceTO resource) throws
CreateException {
try {
this.employeeId = resource.employeeId;
setResourceData(resource);
getResourceDAO().create(resource);
} catch(Exception ex) {
throw new EJBException("Reason:" + ...);
}
return this.employeeId;
}
public String ejbFindByPrimaryKey(String primaryKey)
throws FinderException {
boolean result;
try {
ResourceDAO resourceDAO = getResourceDAO();
result =
resourceDAO.selectByPrimaryKey(primaryKey);
} catch(Exception ex) {
throw new EJBException("Reason:" + ...);
}
if(result) {
return primaryKey;
}
else {
throw new ObjectNotFoundException(...);
}
}
public void ejbRemove() {
try {
// Remove dependent objects
if(this.skillSets != null) {
SkillSetDAO skillSetDAO = getSkillSetDAO();
skillSetDAO.setResourceID(employeeId);
skillSetDAO.deleteAll();
skillSets = null;
}
if(this.blockoutTime != null) {
BlockOutTimeDAO blockouttimeDAO =
getBlockOutTimeDAO();
blockouttimeDAO.setResourceID(employeeId);
blockouttimeDAO.deleteAll();
blockOutTimes = null;
}
// Remove the resource from the persistent store
ResourceDAO resourceDAO = new
ResourceDAO(employeeId);
resourceDAO.delete();
} catch(ResourceException ex) {
throw new EJBException("Reason:"+...);
} catch(BlockOutTimeException ex) {
throw new EJBException("Reason:"+...);
} catch(Exception exception) {
...
}
}
public void setEntityContext(EntityContext context)
{
this.context = context;
}
public void unsetEntityContext() {
context = null;
}
public void ejbActivate() {
employeeId = (String)context.getPrimaryKey();
}
public void ejbPassivate() {
employeeId = null;
}
public void ejbLoad() {
try {
// load the resource info from
ResourceDAO resourceDAO = getResourceDAO();
setResourceData((ResourceTO)
resourceDAO.load(employeeId));
// Load other dependent objects, if necessary
...
} catch(Exception ex) {
throw new EJBException("Reason:" + ...);
}
}
public void ejbStore() {
try {
// Store resource information
getResourceDAO().update(getResourceData());
// Store dependent objects as needed
...
} catch(SkillSetException ex) {
throw new EJBException("Reason:" + ...);
} catch(BlockOutTimeException ex) {
throw new EJBException("Reason:" + ...);
}
...
}
public void ejbPostCreate(ResourceTO resource) {
}
// Method to Get Resource Transfer Object
public ResourceTO getResourceTO() {
// create a new Resource Transfer Object
ResourceTO resourceTO = new
ResourceTO(employeeId);
// copy all values
resourceTO.lastName = lastName;
resourceTO.firstName = firstName;
resourceTO.departmentId = departmentId;
...
return resourceTO;
}
public void setResourceData(ResourceTO resourceTO) {
// copy values from Transfer Object into entity bean
employeeId = resourceTO.employeeId;
lastName = resourceTO.lastName;
...
}
// Method to get dependent Transfer Objects
public Collection getSkillSetsData() {
// If skillSets is not loaded, load it first.
// See Lazy Load strategy implementation.
return skillSets;
}
...
// other get and set methods as needed
...
// Entity bean business methods
public void addBlockOutTimes(Collection moreBOTs)
throws BlockOutTimeException {
// Note: moreBOTs is a collection of
// BlockOutTimeTO objects
try {
Iterator moreIter = moreBOTs.iterator();
while(moreIter.hasNext()) {
BlockOutTimeTO botTO = (BlockOutTimeTO)
moreIter.next();
if (! (blockOutTimeExists(botTO))) {
// add BlockOutTimeTO to collection
botTO.setNew();
blockOutTime.add(botTO);
} else {
// BlockOutTimeTO already exists, cannot add
throw new BlockOutTimeException(...);
}
}
} catch(Exception exception) {
throw new EJBException(...);
}
}
public void addSkillSet(Collection moreSkills)
throws SkillSetException {
// similar to addBlockOutTime() implementation
...
}
...
public void updateBlockOutTime(Collection updBOTs)
throws BlockOutTimeException {
try {
Iterator botIter = blockOutTimes.iterator();
Iterator updIter = updBOTs.iterator();
while (updIter.hasNext()) {
BlockOutTimeTO botTO = (BlockOutTimeTO)
updIter.next();
while (botIter.hasNext()) {
BlockOutTimeTO existingBOT =
(BlockOutTimeTO) botIter.next();
// compare key values to locate BlockOutTime
if (existingBOT.equals(botTO)) {
// Found BlockOutTime in collection
// replace old BlockOutTimeTO with new one
botTO.setDirty(); //modified old dependent
botTO.resetNew(); //not a new dependent
existingBOT = botTO;
}
}
}
} catch (Exception exc) {
throw new EJBException(...);
}
}
public void updateSkillSet(Collection updSkills)
throws CommitmentException {
// similar to updateBlockOutTime...
...
}
...
}
Ez a szócikk részben vagy egészben a Composite entity pattern című angol Wikipédia-szócikk fordításán alapul. Az eredeti cikk szerkesztőit annak laptörténete sorolja fel. Ez a jelzés csupán a megfogalmazás eredetét és a szerzői jogokat jelzi, nem szolgál a cikkben szereplő információk forrásmegjelöléseként.