搜索参考对象

时间:2015-08-21 20:18:48

标签: jspresso

在我当前的项目中,我希望能够在搜索引用对象时创建新对象。这发生在应用程序的几个地方。

例如,我们假设我们有一个城市实体和一个国家实体。 City实体具有对Country实体的强制引用。

在我的用例中,我想创建一个新城市。当我这样做时,我将不得不为新城市分配一个国家。当我点击查找图标时,我会看到所有现有国家/地区的选择对话框。但如果我没有我想要的国家,我必须中止操作,返回国家名单并创建我想分配给我的新城市的新名单。

  1. 是否可以从所有国家/地区的选择对话框中创建新的国家/地区?
  2. 如果可能,国家是否在创建后立即添加到列表中?
  3. 是否可以为国家/地区列表定义范围?例如,如果用户位于欧洲,则仅显示欧洲国家/地区。
  4. 我可以想象,从框架中可以提出很多要求。但我只是给出了一个镜头,也许还给出了一个新的功能想法,这将是很好的。

1 个答案:

答案 0 :(得分:3)

自定义LOV对话框:

您可以通过创建自己的参考字段旁边安装的LOV操作类来轻松自定义LOV对话框。

  • 在对话框中添加新操作(创建操作):
public class LovActionWithCreate<E, F, G> extends LovAction<E, F, G> {

  private IDisplayableAction createAction;

  @Override
  protected void feedContextWithDialog(IReferencePropertyDescriptor<IComponent> erqDescriptor,
                                       IQueryComponent queryComponent, IView<E> lovView, IActionHandler actionHandler,
                                       Map<String, Object> context) {
    super.feedContextWithDialog(erqDescriptor, queryComponent, lovView, actionHandler, context);
    List<IDisplayableAction> defaultLovDialogActions = (List<IDisplayableAction>) context.get(
        ModalDialogAction.DIALOG_ACTIONS);
    defaultLovDialogActions.add(1, getCreateAction());
  }

  /**
   * Gets create action.
   *
   * @return the create action
   */
  protected IDisplayableAction getCreateAction() {
    return createAction;
  }

  /**
   * Sets create action.
   *
   * @param createAction
   *     the create action
   */
  public void setCreateAction(IDisplayableAction createAction) {
    this.createAction = createAction;
  }
}

关键是要覆盖feedContextWithDialog方法,以便将新操作安装到对话框中。

下一步是安装新的LOV操作。您可以为整个应用程序或每个参考视图全局执行:

  • 全局替换LOV操作只需在您的应用程序'lovAction'中声明名为frontend.groovy的操作,即:
action('lovAction', parent: 'lovActionBase', class:'test.LovActionWithCreate',
    custom: [createAction_ref:'theCreateAction']
)
  • 替换表单中某个参考字段的LOV操作可以使用referencePropertyView(在formtable中)及其'lovAction'属性来完成,例如:
action('lovActionWithCreate', parent: 'lovActionBase', class:'test.LovActionWithCreate',
    custom: [createAction_ref:'theCreateAction']
)

form('ACertainForm'){
  fields {
    ...
    referencePropertyView name:'country', lovAction:'lovActionWithCreate'
    ...
  }
}

在LOV对话框中创建实体:

在下一步中,我们创建将负责打开额外对话框以创建新实体的操作,并将其保留,如果成功,则将其添加到LOV结果视图。这有点复杂但不是那么多。

  • 首先,我们必须打开一个新对话框。

为此,我们将继承内置EditComponentAction。此操作的目标是在模式对话框中编辑模型。这里唯一的困难是我们的模型只在运行时才知道。没问题,因为我们将使用Jspresso的动态特性。

public class CreateEntityFromLOVAction<E, F, G> extends EditComponentAction<E,F,G> {

  @Override
  protected Object getComponentToEdit(Map<String, Object> context) {
    IEntityFactory entityFactory = getBackendController(context).getEntityFactory();
    IQueryComponent lovQueryComponent = (IQueryComponent) context.get(IQueryComponent.QUERY_COMPONENT);
    Class<IEntity> entityToCreateContract = lovQueryComponent.getQueryContract();

    IEntity entityInstance = entityFactory.createEntityInstance(entityToCreateContract);
    setActionParameter(Arrays.asList(entityInstance), context);
    return entityInstance;
  }

  @Override
  protected IViewDescriptor getViewDescriptor(Map<String, Object> context) {
    IEntityFactory entityFactory = getBackendController(context).getEntityFactory();
    IQueryComponent lovQueryComponent = (IQueryComponent) context.get(IQueryComponent.QUERY_COMPONENT);
    Class<IEntity> entityToCreateContract = lovQueryComponent.getQueryContract();
    IComponentDescriptor<?> entityToCreateDescriptor = entityFactory.getComponentDescriptor(entityToCreateContract);

    BasicComponentViewDescriptor formViewDescriptor = new BasicComponentViewDescriptor();
    formViewDescriptor.setModelDescriptor(entityToCreateDescriptor);
    return formViewDescriptor;
  }
}

如果您查看上面的代码,我们的新操作会处理以下事项:

  1. 从上下文中获取要创建的实体类型。为此,我们只是探索查询组件,它是LOV对话框的模型。
  2. 创建实体实例并在链接的上下文中将其设置为操作参数以继续处理它(保存,关闭对话框)。
  3. 创建要在创建对话框中显示的表单。
  4. 第1点和第2点由getComponentToEdit方法处理,第3点由getViewDescriptor方法处理。

    • 接下来,当用户点击Ok时,我们必须保存实体,将其添加到LOV结果列表并关闭创建对话框。

    为此,我们将创建一个新操作,并将其链接到saveActioncloseDialogAction内置操作。

    public class CreateEntityFromLOVPersistAction<E, F, G> extends FrontendAction<E,F,G> {
    
      @Override
      public boolean execute(IActionHandler actionHandler, Map<String, Object> context) {
        if (super.execute(actionHandler, context)) {
          IQueryComponent lovQueryComponent = (IQueryComponent) context.get(IQueryComponent.QUERY_COMPONENT);
          List<IEntity> createdEntityInstance = getActionParameter(context);
    
          lovQueryComponent.setQueriedComponents(createdEntityInstance);
          return true;
        }
        return false;
      }
    }
    
    • SJS frontend.groovy中的最终布线:
    action('createEntityFromLovOkAction', parent: 'okDialogFrontAction',
            class:'test.CreateEntityFromLOVPersistAction',
           wrapped: 'saveBackAction', next: 'closeDialogAction')
    
    action('createEntityFromLovAction', parent: 'editComponentAction',
            class: 'test.CreateEntityFromLOVAction',
           name:'add.name', custom: [
               okAction_ref: 'createEntityFromLovOkAction'
           ]
    )
    
    action('lovAction', parent: 'lovActionBase',
            class:'test.LovActionWithCreate',
        custom: [createAction_ref:'createEntityFromLovAction']
    )
    

    少于100行代码的长答案,但现在您有一个完全通用的LOV操作,用户可以在不离开当前屏幕的情况下创建任何缺失的主数据。

    根据用户背景预设LOV过滤器中的一些数据:

    为此,我们通常使用初始化映射,它允许在LOV中查询引用属性时设置一些限制(静态或动态)。例如,让我们考虑以下用例:

    • 您有2个实体ContractTariff,它们通过1-N关系链接在一起,即Contract与1 Tariff相关联。
    • ContractTariff都有country属性,Tariff可以分配给Contract当且仅当他们属于同一个国家/地区时
    • Tarrif具有status属性,只有在Contractstatus的情况下才能在ACTIVE中使用。

    您可以通过以下方式在引用属性上设置初始化映射,在LOV中简单地强制执行这些规则:

    Entity('Contract', ...) {
      ...
      reference 'tariff', ref: 'Tariff',
           initializationMapping: [
                'country': 'country',
                'status': 'ACTIVE'
           ]
      ...
    }
    

    考虑到这一点,这种行为可能会很好地找到框架,所以请随时在Jspresso GitHub中打开增强请求。