一、关于实体对象
实体对象:实体对象为应用表封装了业务逻辑和DML操作; 1.对象模型和关键类
- oracle.apps.fnd.framework.server.==OAEntityCache==:该缓存类用于存储特定实体对象的查询结果集。映射到相同实体对象的多个视图对象共享相同的实体缓存;
- oracle.apps.fnd.framework.server.OAEntityImpl:
- oracle.apps.fnd.framework.server.OAEntityDefImpl:
- oracle.apps.fnd.framework.server.OAEntityExpert:
- oracle.jbo.Key:
二、新增
创建实体对象,必须在相应的视图对象中先调用createRow,然后调用insertRow方法。如下例所示:
// In the application module; this example from the OA Framework
// ToolBox Tutorial will instantiate a SupplierEOImpl.
public void create()
{
OAViewObject vo = getSuppliersVO();
vo.insertRow(vo.createRow());
// Always call this after you perform a row insert. See the Entity Object
// New / Initial section below for additional information.
vo.setNewRowState(Row.STATUS_INITIALIZED);
}
==在视图对象中的CreateRow()方法会调用实体对象中的Create()方法==。可以在实体对象的create()添加默认/初始化代码。 警告:不要放任何初始化逻辑再实体对象的构造器中初始化逻辑应该在create()方法调用super.create(attribute)之后增加。 提示:如果在设计阶段已经确定了默认值,可以在OA扩展中通过设置default value设置默认值。这些值可以被客户定制化。
/**
* In the SupplierEOImpl class; initialize a new supplier.
*/
Public void create(AttributeList attributeList)
{
super.create(attributeList);
OADBTransaction transaction = getOADBTransaction();
// Supplier id is obtained from the table's sequence
Number supplierId =
transaction.getSequenceValue("FWK_TBX_SUPPLIERS_S");
setSupplierId(supplierId);
// Start date should be set to sysdate
setStartDate(transaction.getCurrentDBDate());
} // end create()
提示:==当设置实体对象属性值的时候,调用 set<AttributeName>(val)而不是 setAttribute("<AttributeName>", val)==,因为查询步骤将被忽略,性能会得到提高。如果想跳过任何编程化的校验,但是仍然执行对于某些属性声明的校验,可以调用setAttributeInternal()。
1.组合实体对象关联
在组合关联中,==BC4J会自动的设置父主键的属性值到子实体对象中。父主键值将会传给子类实体对象的create()作为参数,当调用super.create(attributeList)时,被自动设置==。不需要在子类实体对象中,自己构造父类实体对象的主键。
2.实体对象初始化/NEW STATE
默认情况下,被创建的实体对象是STATUS_NEW行状态,BC4J添加它们到校验和提交监听列表。在这种情况下,任何触发校验和数据库提交序列的事件都包括这些实体对象。 当插入新行数据之后,马上在ViewRowImpl通过==调用setNewRowState(STATUS_INITIALIZED)来绕过以上的行为==,同时会设置任何关联实体对象的状态为STATUS_INITIALIZED。 这样,==BC4J会从事务和校验监听列表中移除相应的实体对象,从而不会被校验和提交到数据库==。只要用户通过调用setter()方法改变了实体对象的属性,实体对象的状态就会变为STATUS_NEW,BC4J就会将它交给校验/提交监听列表。可以在ViewRowImpl视图行实现类手动调用setNewRowState(STATUS_NEW)去改变实体对象的状态。
3.典型新增案例
在单行中,平铺Master/Detail
一个订单中可能包含多行,每行中可能又包含许多的商品。尽管BC4J可以为单行视图对象创建不同的实体对象,这些实体对象是不相关的或者是伙伴关系。如果这些对象中的一个是另一个的子类,你就需要进行干预。这种情况下,需要在实体对象的行实现中加入以下自定义的create()方法,确保正确色父类关键值被设置在底层的实体对象:
// The following is required to support the creating the master/detail line
// and shipment entities that have been "flattened" into a single row in
// POLineShipFullVO with a 1:1 join.
//
// If you don't do this, BC4J will automatically treat them like peers and
// try to set the po header id as the parent key for both entities.
protected void create(oracle.jbo.AttributeList nvp)
{
PurchaseOrderLineEOImpl lineEO = (PurchaseOrderLineEOImpl)getEntity(0);
PurchaseOrderShipmentEOImpl shipmentEO = (PurchaseOrderShipmentEOImpl)getEntity(1);
try
{
// Create Lines EO
lineEO.create(nvp);
// Create Shipments EO
shipmentEO.create(lineEO);
// Calling this ensures that any personalization default values
// properly set since the OAF normally sets this in the super.create(), but
// since this is not called in this workaround, we need another method
// to ensure customer defaults are applied.
setDefaultValue();
}
catch (Exception ex)
{
lineEO.revert();
shipmentEO.revert();
if (ex instanceof oracle.jbo.JboException)
{
oracle.jbo.JboException jboEx = (oracle.jbo.JboException)ex;
// Developers have to do the mapping on their own because of the
override.
jboEx.doEntityToVOMapping(getApplicationModule(), new
oracle.jbo.ViewObject[]{getViewObject()});
throw jboEx;
}
throw OAException.wrapperException(ex);
}
} // end create()
4.实体对象缓存
一旦创建,BC4J存储实体对象到事务缓存中。这样做的两个好处是:
- ==在相同根应用模块下的多个视图对象可以共享相同的潜在的实体对象==,这也就意味着其中一个视图对象对实体对象所作的修改,其他引用该实体对象的视图对象马上可以可以看到。
- 即使视图对象行集合被刷新,待确定的改变将会保存在缓存中。 需要明确的是,缓存的存在是非常重要的,因为会显示的与它交互去执行某些校验行为。比如,执行一个唯一性检查,你必须在实体对象缓存和数据库中查询是否存在副本。下面在缓存和数据库中去检查数据的三个主要方式:
4.1 findByPrimaryKey( )方法
==findByPrimaryKey( )方法可以保证首先在缓存中查询是否存在给定的建和实体对象类型,然后再去查询数据库==。这个方法是很有用的,但是可能不是一个你想用的轻量及方法,因为它会实例化任何在数据中匹配的实体对象,她也会拉去所有的实体对象到内存,而不仅仅是查找的keys。但是这哥方法比较适合用在-校验序列生成主键的时候,你并不想找到匹配的的地方。当你需要调用一个方法匹配一个中间层访问的时候,它也是很适合的。 下面是SupplierEOImpl类描述了该方法的使用:
public void setSupplierId(Number value)
{
if (value != null)
{
// Supplier id must be unique. To verify this, you must check both the
// entity cache and the database. In this case, it's appropriate
// to use findByPrimaryKey( ) because you're unlikely to get a match,
// and are therefore unlikely to pull a bunch of large objects into memory.
// Note that findByPrimaryKey() is guaranteed to check all suppliers.
// First it checks the entity cache, then it checks the database.
OADBTransaction transaction = getOADBTransaction();
Object[] supplierKey = {value};
EntityDefImpl supplierDefinition = SupplierEOImpl.getDefinitionObject();
SupplierEOImpl supplier = (SupplierEOImpl)supplierDefinition.findByPrimaryKey(transaction,
new Key(supplierKey));
if (supplier != null)
{
throw new OAAttrValException(OAException.TYP_ENTITY_OBJECT,
getEntityDef().getFullName(), // EO name
getPrimaryKey(), // EO PK
"SupplierId", // Attribute Name
value, // Bad attribute value
"ICX", // Message application short name
"FWK_TBX_T_SUP_ID_UNIQUE"); // Message name
}
}
setAttributeInternal(SUPPLIERID, value);
} // end setSupplierId()
4.2 手动缓存迭代
也可以==手工执行和findByPrimaryKey( )方法相同的实体对象缓存检查。可以分步选择性的执行相同的数据库检查==。这样做的好处是可以避免实例化不需要的实体对象。下面是教程中SupplierEOImpl类的例子:
public void setName(String value)
{
// Since this value is marked as "mandatory," the BC4J Framework will take
// care of ensuring that it's a non-null value. However, if it is null, we
// don't want to proceed with any validation that could result in a NPE.
if ((value != null) || (!("".equals(value.trim()))))
{
// Verify that the name is unique. To do this, we must check both the entity
// cache and the database. We begin with the entity cache.
com.sun.java.util.collections.Iterator supplierIterator =
getEntityDef().getAllEntityInstancesIterator(getDBTransaction());
Number currentId = getSupplierId();
while ( supplierIterator.hasNext() )
{
SupplierEOImpl cachedSupplier =
(SupplierEOImpl)supplierIterator.next();
String cachedName = cachedSupplier.getName();
Number cachedId = cachedSupplier.getSupplierId();
// We found a match for the name we're trying to set, so throw an
// exception. Note that we need to exclude this EO from our test.
If (cachedName != null && value.equalsIgnoreCase(cachedName) &&
cachedId.compareTo(currentId) != 0 )
{
throw new OAAttrValException(OAException.TYP_ENTITY_OBJECT,
getEntityDef().getFullName(), // EO name
getPrimaryKey(), // EO PK
"Name", // Attribute Name
value, // Attribute value
"ICX", // Message product short name
"FWK_TBX_T_SUP_DUP_NAME"); // Message name
}
}
// Now we want to check the database for any occurrences of the supplier
// name. The most efficient way to check this is with a validation view
// object which we add to a special "Validation" application module.
OADBTransaction transaction = getOADBTransaction();
OAApplicationModule vam;
// Look to see if the VAM has already been created in this transaction. If not,
// create it.
vam = (OAApplicationModule)transaction.findApplicationModule("supplierVAM");
if (vam == null)
{
vam = (OAApplicationModule)transaction.createApplicationModule("supplierVAM",
"oracle.apps.fnd.framework.toolbox.schema.server.SupplierVAM");
}
// Now, we use a lightweight "validation" view object to see if a
supplier exists
// with the given name.
SupplierNameVVOImpl valNameVo =
(SupplierNameVVOImpl)vam.findViewObject("SupplierNameVVO");
valNameVo.initQuery(value);
if (valNameVo.hasNext())
{
throw new OAAttrValException(OAException.TYP_ENTITY_OBJECT,
getEntityDef().getFullName(), // EO name
getPrimaryKey(), // EO PK
"Name", // Attribute Name
value, // Attribute value
"ICX", // Message application short name
"FWK_TBX_T_SUP_DUP_NAME"); // Message name
}
}
setAttributeInternal(NAME, value);
} // end setName()
4.3 关联迭代
5.实体状态
三、更新/校验
1.属性级校验 2.跨属性校验 3.实体校验 4.跨实体校验 5.不合适的校验失败处理
四、删除
1.校验和级联删除
五、锁
1.过期数据探测
六、提交
七、回滚
1.回滚的方法 2.不合适的Post处理