当我们给数据库中插入数据的时候,一个比较常见的需求就是进行重复性验证。
那么这个需求在ADF中如何来做呢?首先,要做重复性验证,必须先知道哪几个字段能够唯一确定一条记录。下面我举两中场景以及实现他们的方法:

A. 我需要给不同的报告(report_type_id)配置不同的的模板(template_id),那么这里我就可以通过report_type_id和template_id唯一确定一条配置记录。

对于这个需求,我们需要做以下几步:
1. 在EO配置页面的General标签页上,创建一个Alternate key,包含report_id和template_id两个字段;
2. 在EO配置页面的Business Rules标签页上,创建一个UniqueKey Validation。在Rule Definition标签页上选择第一步创建的Alternate key,之后在Validation Execution标签页上输入验证执行的条件(ReportTypeId != null && TemplateId !=null),最后在Failure Handling标签页上输入错误提示消息。

对于这个需求,上面的配置就可以实现了,不需要写代码;

B. 我需要给不同的报告(report_type_id)配置不同的的模板(template_id),同时我还需要给不同的论文(essay_type_id)配置不同的模板(template_id)。那么这里report_type_id和template_id的组合可以唯一确定一条记录,essay_type_id和template_id的组合也可以唯一确定一条记录。

对于这个需要,如果我们使用上面的方法,就需要建立下面的两个Alternate Key:

Name

Key 1

Key 2

ReportTemplateAltKey  

report_type_id    

tempalte_id

EssayTemplateAltKey   

essay_type_id     

template_id

 
之后再按照上面的步骤分别建立两个UniqueKey Validation,执行条件分别为

验证规则

验证规则执行条件

ReportTemplateAltKeyValidation  

ReportTypeId != null && TemplateId !=null    

EssayTemplateAltKeyValidation    

EssayTypeId != null && TemplateId != null

这样貌似一切都是OK的,但是当我们试图去增加记录的时候就会碰到下面的错误:

oracle.jbo.TooManyObjectsException: JBO-25013: Too many objects match the primary key null.
	at oracle.jbo.server.OracleSQLBuilderImpl.doEntitySelectForAltKey(OracleSQLBuilderImpl.java:931)
	at oracle.jbo.server.EntityImpl.doSelectForAltKey(EntityImpl.java:8280)
	at oracle.jbo.server.EntityImpl.populate(EntityImpl.java:6937)
	at oracle.jbo.server.EntityDefImpl.createRowFromDatabase(EntityDefImpl.java:1569)
	at oracle.jbo.server.EntityDefImpl.findFromDatabase(EntityDefImpl.java:1589)
	at oracle.jbo.server.EntityCache.addForAltKey(EntityCache.java:974)
	at oracle.jbo.server.EntityCache.add(EntityCache.java:533)
	at oracle.jbo.server.ViewRowStorage.entityCacheAdd(ViewRowStorage.java:3146)
	at oracle.jbo.server.ViewRowImpl.entityCacheAdd(ViewRowImpl.java:3666)
	at oracle.jbo.server.QueryCollection.add(QueryCollection.java:2376)
	at oracle.jbo.server.ViewRowSetImpl.insertRowAtInternal(ViewRowSetImpl.java:2266)
	at oracle.jbo.server.ViewRowSetImpl.insertViewRowAt(ViewRowSetImpl.java:2226)
	at oracle.jbo.server.ViewRowSetIteratorImpl.doInsertRow(ViewRowSetIteratorImpl.java:2376)
	at oracle.jbo.server.ViewRowSetIteratorImpl.insertRow(ViewRowSetIteratorImpl.java:2333)
	at oracle.jbo.server.ViewRowSetImpl.insertRow(ViewRowSetImpl.java:3126)
	at oracle.jbo.server.ViewObjectImpl.insertRow(ViewObjectImpl.java:10882)

 

这个错误是因为我们定义了两个Alternate Key,当数据库中已经有下面的数据时:

report_type_id 

essay_type_id  

template_id

null 

1

1

 

而我们又试图插入下面这样新的数据时:

report_type_id 

essay_type_id  

template_id

1

null

1

 

这时候虽然只有ReportTemplateAltKeyValidation会触发,EssayTemplateAltKeyValidation不会触发,但是ADF还是会通过ReportTemplateAltKey和EssayTemplateAltKey分别去查找已经存在的数据(EO缓存中)。当使用ReportTemplateAltKey来查找数据时,显然没有问题,因为只能找到正在新增的这条数据。而当使用EssayTemplateAltKey来查找数据时,因为essay_type_id为空,所以只是通过template_id来查找了,最终导致查找出两条数据,分别是DB中已经存在的一条和新增的一条。这就违反了唯一性的约束,所以报错了。

 

对于这中场景,我们可以使用下面的方案:

1. 创建一个ExistedTemplateVVO,sql如下:

 

SELECT 
    report_type_id, 
    essay_type_id, 
    template_id
FROM TEMPLATE_CONFIG

 

 

2. 创建三个绑定变量templateId, reportTypeId, essayTypeId;


3. 创建一个ExistedTemplateVVOCriteria,查询条件如下:

 

Group
    template_id = :templateId
And Group
    report_type_id = :reportTypeId OR
    essay_type_id = :essayTypeId

 

 

4. 在TemplateConfigEO配置页面的View Accessor标签页上添加ExistedTemplateVVO,并且使用ExistedTemplateVVOCriteria作为默认的查询条件;


5.在TemplateConfigEO配置页面的Business Rules标签页上,创建一个List Validation。在Rule Definition标签页上的List Type选择View Accessor(因为其他的类型都无法把当前插入行的信息作为过滤条件) ,之后在Validation Execution标签页上输入验证执行的条件((ReportTypeId != null || EssayTypeId != null) && TemplateId !=null),最后在Failure Handling标签页上输入错误提示消息。

 

对于这个需求,上面的配置就可以实现了,也不需要写代码。