Összetett entitás programtervezési minta

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]

Szerkezete szerkesztés

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]

Részei szerkesztés

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]

Előnyei szerkesztés

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.

Hátrányai szerkesztés

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:

  • Az összes adat egy beanben való tárolása azt jelenti, hogy egyszerre nagy egységeket kell használni. Nem lehet szabályozni, hogy melyik adatra van éppen szükség, ha kell valami, az magával ránt mindent, ha kell, ha nem.
  • Javában az ejbStore() metódust fel kell okosítani, hogy elkerülje a frissítések feljegyzését azokat az eseteket kivéve, amikor az egész objektum állapota változik meg.
  • A perzisztenciát kezelő kód karbantartása is nehézkessé válhat.[2]

Példa kód szerkesztés

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...
    ...
  }

  ...

}

[1]

Jegyzetek szerkesztés

  1. a b c d e f Core J2EE Patterns - Composite Entity. Oracle . Oracle. (Hozzáférés: 2016. február 6.)
  2. Johnson, R.. Expert One-on-One J2EE Design and Development. Indianapolis: Wiley Publishing, Inc, 290. o. (2003) 

Fordítás szerkesztés

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.