当我们给数据库中插入数据的时候,一个比较常见的需求就是进行重复性验证。
那么这个需求在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标签页上输入错误提示消息。
对于这个需求,上面的配置就可以实现了,也不需要写代码。