EBS OAF开发中的弹性域(Flexfields)-关键性弹性域
(版权声明,本人原创或者翻译的文章如需转载,如转载用于个人学习,请注明出处;否则请与本人联系,违者必究)
总览
一个弹性域是一些字段的占位符集,可以由客户为他们的组织配置使用。一旦配置完,集合中的用户定义的字段(label/widget pairs)可以出现在form或者表布局中.集合中的每个字段都有一个名称和一个有效的值集.共有两种弹性域,关键弹性域和描述弹性域。
关键弹性域为Oracle E-Business Suite 提供了一种代表对象的方式,比如科目代码,组件编号,或者工作描述,并且都是由多个字段(部分)作为连接起来的一个单独对象。比如,科目关键弹性域就是在Oracle E-Business Suite中代表了多个科目编码的关键弹性域。
简单来说,描述性弹性域为Oracle E-Business Suite在应用中的客制化提供了灵活的方式,也提供了实现上下文敏感字段的方法,使字段在需要的时候才出现。大体上,描述性弹性域允许页面的客制化既不用写XML也不用写Java,仅需要在一个页面配置的字段集合,就像核心应用中的字段一样。
两种弹性域都允许你客制化Oracle E-Business Suite中的功能而不需要编程,并且这些客制化在OracleE-Business Suite中完全支持。
注意:这个文档假设你具有弹性域的工作知识.如果你不熟悉弹性域,或者你需要更多的信息,请参考Oracle E-Business SuiteFlexfields Guide Release 12 and Chapter 14 ("Flexfields") in the Oracle E-Business Suite Developer‘s GuideRelease 12 .
内容
l 概览
? OAF框架支持和不支持的弹性域功能
l 描述性弹性域
? 在OracleE-Business Suite中建立一个描述性弹性域
? 在JDeveloper中的声明式实现
u 描述性弹性域段列表
? 运行时控制
? 个性化考虑
? 描述性弹性域使用限制
OAF框架支持和不支持的弹性域功能
下面的表格列出了OAF框架支持和不支持的弹性域功能(多于正常的弹性域功能)。
注意:如果一个弹性域在使用OAF框架不支持的功能,那么在Form的弹性域管理界面设置时就会弹出警告。
弹性域功能 | 支持 | 不支持 |
常规 |
l 为描述性弹性域的一个特定的上下文指明分段 l 为关键性和描述性弹性域隐藏特定的分段 l 为关键性和描述性弹性域设置只读分段 l 描述性弹性域的默认值 l 使用引用字段 | l 查询关键性弹性域字段的一个范围 |
值集 |
l 格式化规则 l 显示为弹出式列表 l 显示为LOV l 使用一个$FLEXT$引用 l 使用一个$PROFILES$引用 |
|
验证类型 |
l 无(None) l 独立 l 依赖 l 表 |
l 对(Pair) l 特殊(Special) |
关键性弹性域专有 |
l 动态插入 l 表中的关键性弹性域 l 一个页面中的多个关键性弹性域 l 一个表中的多个关键性弹性域 l 生成CCID l 绑定LOVUI ? 需要关键性弹性域的LOV ? 动态插入 ? 基于LOV的LOV 添加VRule到关键性弹性域web bean | l 指明一个分段的描述 |
描述性弹性域专有 |
l 上下文的值 l 上下文切换 l 通过API设置上下文的值 l 表中的描述性弹性域 l 一个页面中的多个描述性弹性域 l 一个表中的多个描述性弹性域 l 设置一个弹性域为只读 l 隐藏和显示上下文 | l 指明一个分段的描述 |
弹性域核心UI |
l 日期选取器-同时支持关键性和描述性弹性域. l 多个关键性和描述性弹性域使用相同的视图对象 l 编程实现关键性和描述性弹性域 l 把弹性域合并到它的布局中(参考关键性和描述性弹性域的变通方法) |
|
弹性域验证 | l 打开/关闭未验证的提交 |
|
弹性域客制化 | l 覆盖一个描述性弹性域分段的LOV来为多个描述性弹性域设置值 |
|
分段列表 |
l 启用/禁用,重排和把描述性和关键性弹性域标记为只读 l 为关键性和描述性弹性域绑定只读和生成属性 |
|
和其它组件一起使用弹性域 |
l 查询web bean(关闭验证) l MessageLayout区域中的描述性和关键性弹性域 l 如果父页面是内嵌JTT应用中,就会生成内嵌模式的弹性域 l HGrid l Table Detail Disclosure |
l 在头体页面里的描述性弹性域 l Table-in-Table-如果尝试在Table-in-Table实现弹性域,就会抛出一个开发模式错误。 |
PPR支持 |
l 描述性弹性域上下文切换 l 依赖LOV PPR l 使用描述性或者关键性弹性域作为PPR事件的目标 |
|
导出 |
l 描述性弹性域数据 l 关键性弹性域数据 |
|
描述性弹性域
一个描述性弹性域是由类oracle.apps.fnd.framework.webui.beans.OADescriptiveFlexBean实现的。
一个OADescriptiveFlexBean自动生成用于分段值输入的布局。对每个描述性弹性域,如果Display Context属性设置为True,一个context字段将在第一行生成为弹出式列表。第一行之后,任意定义的全局分段都会生成,然后生成是依赖上下文的字段,这些字段会根据选择的context字段的值生成。
每个描述性弹性域分段都有一个右对齐的提示,一个相应的输入字段左对齐。下面的图1是一个标准垂直布局的弹性域UI的示例.
图1一个页面上既有关键性和描述性弹性域的示例
上面的示例显示了一个描述性弹性域,Packaging Type是描述性弹性域的上下文字段,Warehouse是一个全局字段。因为上下文字段没选择,所以在这个例子中没显示任何上下文敏感的元素.
当前的弹性域支持以下三种输入类型:
l 文本输入(不像上面显示的)
l 弹出式列表,就像上面显示的PackagingType
l LOV,就像上面显示的Warehouse
当你添加一个OADescriptiveFlexBean到你的页面时,它:
l 显示弹性域的分段,允许输入,更新和使用相应视图对象中数据库的值填充分段。
l 当选择一个新的上下文时,自动使用相应弹性域分段刷新弹性域
l 验证弹性域分段的输入值
l 自动把有效的值传入视图对象,这样如果没有错误,调用页面访问有效的弹性域的值。如果有错误发生,当前页面将会重画以显示错误消息。
l 如果你需要为一个描述性弹性域的消息文本输入中的长文本换行,你可以在描述性弹性域bean调用processFlex()方法之前使用下面的方法调用setWrapEnabled().
dffBean.setWrapEnabled(true);
默认换行是禁用的。
PPR支持
OAF框架在以下方式中为描述性弹性域提供了支持:
l 如果改变描述性弹性域的上下文,OAF框架使用PPR事件来生成新上下文的分段。
注意:如果控制器代码把描述性弹性域的分段beans移出描述性弹性域容器,OAF框架将进行页面刷新而不是PPR事件。
l 如果PPR事件发生在页面上,任意描述性弹性域的视图属性如果在processFormRequest方法中发生了改变,OAF框架自动把弹性域web bean添加为PPR事件的目标并重新生成描述性弹性域。
注意:如果描述性弹性域的上下文属性在processFormRequest方法中发生了改变,弹性域web bean是不会添加为PPR事件的目标,因此你看不到描述性弹性域结构的变化。为了显示结构上的改变,OAF框架必须重导向到同一个页面,在这种情况下,如果你担心这个,就需要添加相应代码到processRequest方法中。
在OracleE-Business Suite中设置一个描述性弹性域
在添加一个弹性域到OAF框架页面之前,你必须先要在Oracle E-Business Suite中设置描述性弹性域.要做这个,参考Chapter3 ("Planning and Defining Descriptive Flexfields") in the Oracle E-Business Suite Flexfields GuideRelease 12.
如果你对想要设置的描述性弹性域有清晰的机会,对下面的步骤的详细说明,请参考
"Implementing DescriptiveFlexfields" in Chapter 14 ("Flexfields") of the Oracle E-Business Suite Developer‘s GuideRelease 12 中相应的部分.
步骤1:在数据库中定义描述性弹性域的列.
步骤2:在Oracle Application Object Library中注册你的描述性弹性域。
步骤3:使用描述性弹性域窗口注册你的描述性弹性域.
接下来,参考Oracle E-Business Suite Flexfields GuideRelease 12关于下面通用步骤的说明:
步骤4:在值集窗口定义值集,就像在第五章中的描述(“值和值集”)。
步骤5:使用描述性弹性域分段窗口定义你的描述性弹性域结构,就像第三章("Planning and Defining Descriptive Flexfields")中”描述性弹性域分段窗口”部分描述的。
描述性弹性域上下文字段的值决定了描述性弹性域上下文,上下文依赖的分段将会显示出来。在第三章("Planning and Defining Descriptive Flexfields")中”上下文字段和引用字段”部分介绍了更多关于上下文字段的细节。
步骤6:当你准备往OAF框架页面添加描述性弹性域,请参考下面的”声明式实现”和”运行时控制”.
声明式实现
下面的步骤描述了如果如何添加描述性弹性域item到OAF框架区域:
步骤0:确保区域内潜在的视图包含了这个描述性弹性域需要的所有数据库字段.。你不应该为这个弹性域改变数据库列的名称,因为OADescriptiveFlexBean使用和视图对象生成方式同样的命名转换方式,这样才可以从视图对象中找到相应的属性。
步骤1:在你的区域中定义一个item类型为flex的item。
注意:你不能直接在messageComponentLayout区域下窗机一个flex item,但是你可以在messageComponentLayout区域下创建一个mesageLayout区域,并在messageLayout区域下创建一个flex item.
步骤2:设置Read Only属性为True或者False,依赖于你是否想让描述性弹性域只读。
步骤3:为你的弹性域指定一个视图对象实例,视图对象实例应该和在区域上指定的视图实例(视图对象)一样。
注意:OAF框架支持在同一个视图对象上的多个描述性弹性域。
注意:如果一个弹性域视图对象没有返回一行,OAException会被抛出,这样控制器的processRequest方法仍可以运行并生成弹性域。
步骤4:设置Appl Short Name属性为注册了描述性弹性域的应用的简写名。(Step 3 of Setting Up a Descriptive Flexfield inOracle Applications).
步骤5:设置Name属性为注册描述性弹性域的名称。
注意:这和如何由速记编码定义关键性弹性域不同。
步骤6:设置Type 属性为descriptive.
步骤7:根据需要设置分段列表属性(参看描述性弹性域分段列表).
步骤8:最后,你可以设置Display Context Field为True或者False。依赖于是否你想显示或者隐藏描述性弹性域的上下文。
描述性弹性域分段列表
如果你把属性Segment List留为空,所有分段都生成.这个属性的值你必须使用下面的格式:
Global Data Elements|[global segment1]|[globalsegment2]||...||Context1|[segment1 for context1]|[segment2 forcontext1]||...||Context2|....
在图1中显示的示例,Packaging Type是上下文字段,Warehouse是描述性弹性域的全局性字段。为了显示Warehouse全局字段和为Box上下文显示上下文相关的字段Items per Box和Box Size,为Pallet上下文显示Items per Pallet和Pallet Weight,你必须为Segment List属性指定为下面的值:
Global Data Elements|Warehouse||Box|Itemsper Box|Box Size||Pallet|Items per Pallet|Pallet Weight
就像上面显示的,一个特定上下文的分段是由”|”隔开的,但不同上下文的数据是由”||”隔开的。
只读字段.
你也可以在列表中的任一分段添加只读标记($RO$),比如,下面集合中的($RO$)指示Segment1为只读:
Context1|Segment1($RO$)|Segment2...
运行时控制
注意:你应该仅在不能声明创建描述性弹性域的时候通过程序创建web beans。编程创建的web beans不可以个性化,重用或者简单的扩展.
当创建web bean控制代码时,你可以参考OA Framework Controller CodingStandards 中需要考虑的额外信息.
如果你声明式的创建了你的描述性弹性域,你仅需要在你的控制器中的processRequest方法添加下面示例中类似的代码,DescFF是你的区域中item的名字(item 类型为flex)。
OADescriptiveFlexBean dffBean = (OADescriptiveFlexBean) createWebBean(pageContext, DESCRIPTIVE_FLEX_BEAN, null, "DescFF"); webBean.addIndexedChild(dffBean); dffBean.setAttributeValue(OAWebBeanConstants.VIEW_USAGE_NAME,"FlextestVO1"); dffBean.setAttributeValue(OAWebBeanConstants.FLEXFIELD_APPLICATION_SHORT_NAME, "FND"); dffBean.setAttributeValue(OAWebBeanConstants.REGION_APPLICATION_ID, new Integer(0)); dffBean.setAttributeValue(OAWebBeanConstants.FLEXFIELD_NAME,"SimpleFlex");
在processFormRequest方法中,你可以从你的视图对象中的相应属性中得到有效的描述性弹性域数据而不需要额外的编码。
你也应考虑描述性弹性域其它的问题
l 和父布局合并描述性弹性域分段
l 更新弹性域UI布局
l processRequest方法
l 重写描述性弹性域上下文的值
l 主/体页面中的描述性弹性域
l 查询区域中的描述性弹性域
l 只读和生成绑定值
l 为描述性弹性域设置默认值
l 重写描述性弹性域的分段LOV
为父布局合并描述性弹性域分段
默认,弹性域分段只在他们本身内部对齐,但在父布局中时不对齐的。如果你想要合并描述性弹性域分段到父布局,你必须根据属性找到OADescriptiveFlexBean或者在你的控制器的processRequest方法调用oracle.apps.fnd.framework.webui.beans.OADescriptiveFlexBean的方法mergeSegmentsWithParent。
下面的代码示例合并了描述性弹性域分段到了父布局中:
public class RegionCO extends OAControllerImpl { public void processRequest(OAPageContext pageContext, OAWebBean webBean) { super.processRequest(pageContext, webBean); //find the flexfield that is defined in this region as the item "DescFF" and merge each //individual segment to the outside layout OADescriptiveFlexBean dffBean = (OADescriptiveFlexBean)webBean.findIndexedChildRecursive("DescFF"); flexBean.mergeSegmentsWithParent(pageContext); } public void processFormRequest(OAPageContext pageContext, OAWebBean webBean) { super.processFormRequest(pageContext, webBean); } }
比如,你可以添加下面的行到上面的”创建描述性弹性域”的代码示例后面.
dffBean.mergeSegmentsWithParent(pageContext);
更新弹性域UI布局
注意:OAF框架组不建议这么做,可能引起PPR事件的问题.
如果你想使用描述性弹性域做一些不寻常的事情(比如在每个分段后面添加一个按钮或者移动分段),你需要做下面的步骤:
1. 通过属性名找到OADescriptiveFlexBean,调用OADescriptiveFlexBean的方法processFlex。然后,你就会基于元数据和视图对象属性创建弹性域分段的web beans.
l 调用弹性域web bean上的getIndexedChild(int)方法来遍历弹性域的分段并根据需要更新布局。
processRequest方法
如果你更改了描述性弹性域上下文的值,描述性弹性域代码必须导回到同一页面.控制器的processRequest方法将再次被调用。如果这在页面上导致了问题,那么请在你的processRequest方法中使用下面的代码.
public void processRequest(OAPageContext pageContext, OAWebBean webBean) {String formEvent = pageContext.getParameter(FLEX_FORM_EVENT); if (formEvent == null ) { //processRequest ... } }
改写描述性弹性域的上下文的值
如果你要使用一个不是从视图对象中得来的值改写描述性弹性域上下文的值,你可以使用OADescriptiveFlexBean的setFlexContext方法来这么做.
在主/详细页面上的描述性弹性域
假设你实现了一个主/体页面,当用户在主区域选择了一个单选按钮来选择一行,发出一个PPR事件.页面控制器然后运行方法processFormRequest来侦测单选按钮并调用应用模块中的方法来主数据集中在显示在详细区域。
如果你想添加一个描述性弹性域到详细区域,你可以使用下面的变通方法来更改你的控制器代码来保证当主表中选择不同的行时,你的描述性弹性域使用了正确的上下文。
public void processFormRequest(OAPageContext pageContext, OAWebBean webBean) { super.processFormRequest(pageContext, webBean); pageContext.getApplicationModule(webBean).invokeMethod("refreshDetail"); pageContext.setForwardURLToCurrentPage(null,true,null,(byte)0); } public void refreshDetail() { Row[] rows = getFndApplicationVO().getFilteredRows("selection","Y"); if (rows != null) { getFndApplicationVO().setCurrentRow(rows[0]); } }
查询区域中的描述性弹性域
目前如果一个查询区域包含一个描述性弹性域,并且这个弹性域有个LOV类型的分段,任何你在弹性域LOV指定的查询条件将会自动验证LOVs,但是,在查询区域,是不应该做验证的.要关闭验证,可以使用OADescriptiveFlexBean里下面的API:
public void setUnvalidated(boolean unvalidated);
如果这个方法的unvalidated 值是true,OAF框架将为这个描述性弹性域禁止LOV验证并禁止服务端验证.更多细节参考弹性域验证.
只读和生成绑定值
如果你不得不在表中实现弹性域,并且弹性域是只读或者只在一些行中生成,而不在其它行中生成,你可以通过编程来使用绑定值实现。目前不可以通过声明来实现。
首先,使用OADataBoundValueViewObject或者一些其它的绑定值类来创建绑定值,然后在控制器的processRequest方法中设置属性如下面示例所示:
dffBean.setAttributeValue(READ_ONLY_ATTR,boundValue);或者
dffBean.setAttributeValue(RENDERED_ATTR,boundValue);
为描述性弹性域设置默认值
之前,当生成描述性弹性域时,如果你想显示分段的默认值,你不得不使用oracle.apps.fnd.framework.OAFlexUtils的API
populateRowWithDFFDefaultValues,这个API将使用描述性弹性域的默认值来设置视图对象行。现在,无论何时创建一个新的行,OAF框架都会自动显示默认值.如果当前行是从数据库加载的,描述性弹性域显示存储于数据库中的值。
重载描述性弹性域的分段LOV
在OAF框架, 描述性弹性域分段的LOV自动映射到那个分段的SQL查询条件和结果.尽管如此,有可能你想关联一个描述性弹性域的多个分段到一个分段LOV结果上。换句话说,你可能想重载一个分段的LOV那么当一个用户从分段LOV选择一个值,LOV也会为所有关联弹性域分段返回值.你可以通过编程重载分段LOV,使用OADescriptiveFlexBean的下面方法
public void setFlexLovOverrideInfo(Dictionary[]flexLovInfo)
flexLovInfo参数是一个dictionariy数组.这些dictionariy包含必要的来重载弹性域LOV的关系,那么分段LOV也会为基页面的这个弹性域的多个其它分段返回值。每个dictionary包含下列属性,并在Javadoc中有详细的解释:
l FLEX_LOV_OVERRIDE_SEGMENT - 弹性域分段的数据库列名,就是要覆盖的分段的LOV
l FLEX_LOV_OVERRIDE_RESULTS -弹性域分段的数据库列名的字符串数组,这些分段是你想关联LOV来重载或者返回结果
l FLEX_LOV_OVERRIDE_VIEWUSAGE -包含SQL的视图对象的实例名称,用来覆盖LOV分段
l FLEX_LOV_OVERRIDE_AM包含FLEX_LOV_OVERRIDE_VIEWUSAGE指定的视图对象的应用模块的完全路径.
下面的代码演示了如何使用这个API:
//Create a dictionary array and use arrayMap for each dictionary Dictionary[] flexLovOverrideInfo = new Dictionary[1]; for (int i = 0; i< flexLovOverrideInfo.length; i++) { flexLovOverrideInfo[i] = new ArrayMap(4); } //Specify AM and VO name for the overriden LOV flexLovOverrideInfo[0].put(FLEX_LOV_OVERRIDE_VIEWUSAGE, "USCityLovVO"); flexLovOverrideInfo[0].put(FLEX_LOV_OVERRIDE_AM, "oracle.apps.per.selfservice.personalinformation.server.AddressUpdateAM"); //The LOV result will be returned to the following segments, //and in the new LOV VO, there should be a corresponding column //for each segment. If the VO column name is different than the //segment name, the name should be specified as "segmentName:lovColumnName". //For example: "POSTAL_CODE:ZIP_CODE" String[] flexLovOverrideResults = new String[4]; flexLovOverrideResults[0] = "TOWN_OR_CITY"; flexLovOverrideResults[1] = "REGION_2"; flexLovOverrideResults[2] = "POSTAL_CODE:ZIP_CODE"; flexLovOverrideResults[3] = "REGION_1"; flexLovOverrideInfo[0].put(FLEX_LOV_OVERRIDE_RESULTS, flexLovOverrideResults); //The LOV will be attached on this segment: flexLovOverrideInfo[0].put(FLEX_LOV_OVERRIDE_SEGMENT, "TOWN_OR_CITY"); //Set the override info into flexfield web bean. flexBean.setFlexLovOverrideInfo(flexLovOverrideInfo);
描述性弹性域使用限制
1. 仅当描述性弹性域上下文依赖的分段在表中有相同的结构时,才在表或者高级表中支持弹性域.表中表示不支持描述性弹性域的.如果从一个表中显示描述性弹性域信息,根据上下文,结构可能差别很大,那么你必须实现主/详细页面并在单独的详细页面显示描述性弹性域的结构.
2. 在一个单独表和单独的视图对象中支持多个描述性弹性域,但是不同的弹性域使用的属性不应该有重叠部分,否则它们将覆盖彼此的值.
既然不能更改弹性域web bean使用的视图对象的属性映射(比如,它自动使用Segment1视图对象属性如果一个分段使用表中SEGMENT1列),你需要为其它弹性域使用OADescriptiveFlexBean的方法setFlexPrefix来定义前缀。
为说明这个,假设描述性弹性域DFF1使用ATTRIBUTE1和ATTRIBUTE2,并映射到视图对象属性Attribute1和Attribute2.描述性弹性域DFF2使用属性ATTRIBUTE2和ATTRIBUTE3,并映射到Attribute2和Attribute3.如果没有前缀,两个弹性域都更新视图对象的Attribute2,那么其中之一的值会被覆盖.
如果你调用DFF2Bean.setFlexPrefix("DFF2"), DFF2 OADescriptiveFlexBean会映射到DFF2Attribute2和DFF2Attribute3,因此,将不会和DFF1 OADescriptiveFlexBean的属性冲突.
3. 参考已知弹性域问题来参考其它限制.