管理方案--无代码/低代码的方法

134 阅读6分钟

在这篇博客中,让我们看看在BTP平台上的ABAP的管理场景(行为实现)。

正如标题中所提到的,管理场景与无/低代码概念携手并进。 由于管理方式承担了CRUD操作的所有责任,我们只需要考虑到某些授权(如果我们要实现授权对象和相关对象)。

让我们考虑以下情况。

我们有一个学生门户应用程序,有一个头表和另外两个子表。

学生头表。

@EndUserText.label : 'Header  for Student'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table ystudent_hdr {
  key client   : abap.clnt not null;
  key sid      : sysuuid_x16 not null;
  admission_no : abap.char(10);
  fname        : abap.char(25);
  mname        : abap.char(25);
  lname        : abap.char(25);
  contact_no1  : abap.char(10);
  contact_no2  : abap.char(10);
  dob          : abap.dats;
  gender       : ydgender;
  semail       : abap.char(50);
  pemail       : abap.char(50);
  paddress     : abap.string(256);
  caddress     : abap.string(256);
  blood_group  : ydbg;
  height       : abap.dec(4,4);
  weight       : abap.dec(4,4);

}

学生学业详情。

@EndUserText.label : 'Current Academic Details'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table yst_cracademic {
  key client   : abap.clnt not null;
  @AbapCatalog.foreignKey.screenCheck : false
  key sid      : sysuuid_x16 not null
    with foreign key ystudent_hdr
      where client = yst_cracademic.client
        and sid = yst_cracademic.sid;
  key course   : ydcourse not null;
  key semester : ydsemester not null;
  status       : ydsemstat;
  percentage   : abap.dec(3,2);
  feedback     : abap.string(256);

}

学生出勤情况。

@EndUserText.label : 'Current Academic Details'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table yst_cracademic {
  key client   : abap.clnt not null;
  @AbapCatalog.foreignKey.screenCheck : false
  key sid      : sysuuid_x16 not null
    with foreign key ystudent_hdr
      where client = yst_cracademic.client
        and sid = yst_cracademic.sid;
  key course   : ydcourse not null;
  key semester : ydsemester not null;
  status       : ydsemstat;
  percentage   : abap.dec(3,2);
  feedback     : abap.string(256);

}

以下CDS实体代表父子层次结构。

头表。

@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Student Header'
@Metadata.allowExtensions: true
define root view entity YSTUDENT_HDR_I
  as select from ystudent_hdr
  composition [0..*] of YST_CRACADEMIC_I as _academic
  composition [0..*] of YST_ATTENDANCE_I as _attendance
  association to YI_GENDER               as _gender on $projection.gender = _gender.Value
  association to YI_BG                   as _bg     on $projection.blood_group = _bg.Value
{
  key sid,
      admission_no,
      fname,
      mname,
      lname,
      contact_no1,
      contact_no2,
      dob,
      gender,
      _gender.Description as genderdesc,
      semail,
      pemail,
      paddress,
      caddress,
      blood_group,
      _bg.Description     as bg_desc,
      height,
      weight,
      _academic,
      _attendance,
      _gender,
      _bg
      //    _association_name // Make association public
}

元数据扩展。

@Metadata.layer: #CORE
@UI: {
    headerInfo: { typeName: 'Student Detail',
                  typeNamePlural: 'Student Details',
                  
                  title: { type: #STANDARD, label: 'Student Details', value: 'fname' },
                  description:{ type: #STANDARD , label: 'Student Details' , value : 'lname'}

    },
    presentationVariant: [{ sortOrder: [{by: 'fname', direction: #ASC}]  }]


}
@Search.searchable: true
annotate view YSTUDENT_HDR_I with
{
  @UI.facet: [{ id: 'Student',
                  purpose: #STANDARD,
                  type: #IDENTIFICATION_REFERENCE,
                  label: 'Student Details',
                  position: 10
     },
     { id: 'Academic',
  purpose: #STANDARD,
  type: #LINEITEM_REFERENCE,
  label: 'Academic Details',
  position: 20,
  targetElement: '_academic'},
     { id: 'Attendance',
  purpose: #STANDARD,
  type: #LINEITEM_REFERENCE,
  label: 'Attendance Details',
  position: 20,
  targetElement: '_attendance'}]

  @UI: { identification: [{ position: 10, label: 'Student ID' }] }
  @UI.hidden: true
  sid;
  @UI: { lineItem:       [{ position: 20, importance: #HIGH, label: 'Admission Number' }],
         identification: [{ position: 20, label: 'Admission Number' }] }
  @Search.defaultSearchElement: true
  admission_no;
  @UI: { lineItem:       [{ position: 30, importance: #HIGH, label: 'First Name' }],
     identification: [{ position: 30, label: 'First Name' }] }
  @Search.defaultSearchElement: true
  fname;
  @UI: { lineItem:       [{ position: 40, importance: #HIGH, label: 'Middle Name' }],
     identification: [{ position: 40, label: 'Middle Name' }] }
  mname;
  @UI: { lineItem:       [{ position: 50, importance: #HIGH, label: 'Last Name' }],
     identification: [{ position: 50, label: 'Last Name' }] }
  @Search.defaultSearchElement: true
  lname;
  @UI: { lineItem:       [{ position: 60, importance: #HIGH, label: 'Contact Number 1' }],
     identification: [{ position: 60, label: 'Contact Number 1' }] }
  contact_no1;
  @UI: { lineItem:       [{ position: 70, importance: #HIGH, label: 'Contact Number 2' }],
     identification: [{ position: 70, label: 'Contact Number 2' }] }
  contact_no2;
  @UI: { lineItem:       [{ position: 80, importance: #HIGH, label: 'Date of Birth' }],
     identification: [{ position: 80, label: 'Date of Birth' }] }
  dob;
  @UI: { lineItem:       [{ position: 90, importance: #HIGH, label: 'Gender' }],
     identification: [{ position: 90, label: 'Gender' }] }
  @Consumption.valueHelpDefinition: [{ entity:
  {name: 'YI_GENDER' , element: 'Value' },
  additionalBinding: [{ localElement: 'genderdesc', element: 'Description' }]
  }]
  gender;
  @UI: { lineItem:       [{ position: 100, importance: #HIGH, label: '' }],
    identification: [{ position: 100, label: '' }] }
  genderdesc;
  @UI: { lineItem:       [{ position: 110, importance: #HIGH, label: 'Student Email' }],
     identification: [{ position: 110, label: 'Student Email' }] }
  semail;
  @UI: { lineItem:       [{ position: 120, importance: #HIGH, label: 'Parent Email' }],
     identification: [{ position: 120, label: 'Parent Email' }] }
  pemail;
  @UI: { lineItem:       [{ position: 130, importance: #HIGH, label: 'Parent Address' }],
     identification: [{ position: 130, label: 'Parent Address' }] }
  paddress;
  @UI: { lineItem:       [{ position: 140, importance: #HIGH, label: 'Student Address ' }],
      identification: [{ position: 140, label: 'Student Address ' }] }
  caddress;
  @UI: { lineItem:       [{ position: 150, importance: #HIGH, label: 'Blood Group' }],
     identification: [{ position: 150, label: 'Blood Group' }] }
  @Consumption.valueHelpDefinition: [{ entity:
  {name: 'YI_BG' , element: 'Value' },
  additionalBinding: [{ localElement: 'bg_desc', element: 'Description' }]
  }]
  blood_group;
  @UI: { lineItem:       [{ position: 160, importance: #HIGH, label: '' }],
     identification: [{ position: 160, label: '' }] }
  bg_desc;
  @UI: { lineItem:       [{ position: 170, importance: #HIGH, label: 'Height in CM' }],
  identification: [{ position: 170, label: 'Height in CM' }] }
  height;
  @UI: { lineItem:       [{ position: 180, importance: #HIGH, label: 'Weight in KG' }],
     identification: [{ position: 180, label: 'Weight in KG' }] }
  weight;

}

学业细节。

@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Academic Details'
@Metadata.allowExtensions: true
define view  entity  YST_CRACADEMIC_I
  as select from yst_cracademic
  association to parent YSTUDENT_HDR_I as _HDR      on $projection.sid = _HDR.sid
  association to YI_COURSE             as _course   on $projection.course = _course.Value
  association to YI_SEMESTER           as _semester on $projection.semester = _semester.Value
  association to YI_SEMSTAT           as _stat on $projection.status = _stat.Value
{
  key sid,
  key course,
  key semester,
      _course.Description   as course_desc,
      _semester.Description as semester_desc,
      status,
      _stat.Description as semester_status,
      percentage,
      feedback,
      _HDR // Make association public
}

元数据扩展。

@Metadata.layer: #CORE

@UI: {
    headerInfo: { typeName: 'Academic Detail',
                  typeNamePlural: 'Academic Details',
                
                  title: { type: #STANDARD, label: 'Academic Details', value: 'course' },
                  description:{ type: #STANDARD , label: 'Academic Details' , value : 'course_desc'}

    },
    presentationVariant: [{ sortOrder: [{by: 'semester', direction: #ASC}]  }]


}
@Search.searchable: true
annotate view YST_CRACADEMIC_I with
{
  @UI.facet: [{ id: 'Acadmic',
                  purpose: #STANDARD,
                  type: #IDENTIFICATION_REFERENCE,
                  label: 'Academic Details',
                  position: 10
     }]
  @UI: { identification: [{ position: 10, label: 'Student ID' }] }
  @UI.hidden: true
  sid;
  @UI: { lineItem:       [{ position: 20, importance: #HIGH, label: 'Course' }],
   identification: [{ position: 20, label: 'Course' }] }
  @Search.defaultSearchElement: true
  @Consumption.valueHelpDefinition: [{ entity:
  {name: 'YI_COURSE' , element: 'Value' },
  additionalBinding: [{ localElement: 'course_desc', element: 'Description' }]
  }]
  course;
  @UI: { lineItem:       [{ position: 30, importance: #HIGH, label: '' }],
      identification: [{ position: 30, label: '' }] }
  @Search.defaultSearchElement: true
  course_desc;
  @UI: { lineItem:       [{ position: 40, importance: #HIGH, label: 'Semester' }],
      identification: [{ position: 40, label: 'Semester' }] }
  @Search.defaultSearchElement: true
  @Consumption.valueHelpDefinition: [{ entity:
  {name: 'YI_SEMESTER' , element: 'Value' },
  additionalBinding: [{ localElement: 'semester_desc', element: 'Description' }]
  }]
  semester;
  @UI: { lineItem:       [{ position: 50, importance: #HIGH, label: '' }],
      identification: [{ position: 50, label: '' }] }
  @Search.defaultSearchElement: true
  semester_desc;
  @UI: { lineItem:       [{ position: 60, importance: #HIGH, label: 'Status' }],
  identification: [{ position: 60, label: 'Status' }] }
  @Search.defaultSearchElement: true
  @Consumption.valueHelpDefinition: [{ entity:
  {name: 'YI_SEMSTAT' , element: 'Value' },
  additionalBinding: [{ localElement: 'semester_status', element: 'Description' }]
  }]
  status;
  @UI: { lineItem:       [{ position: 70, importance: #HIGH, label: '' }],
   identification: [{ position: 70, label: '' }] }
  @Search.defaultSearchElement: true
  semester_status;
  @UI: { lineItem:       [{ position: 80, importance: #HIGH, label: 'Percentage Scored' }],
  identification: [{ position: 80, label: 'Percentage Scored' }] }
  @Search.defaultSearchElement: true
  percentage;
  @UI: { lineItem:       [{ position: 90, importance: #HIGH, label: 'Student Feed Back' }],
   identification: [{ position: 90, label: 'Student Feed Back' }] }
  @Search.defaultSearchElement: true
  feedback;

}

出勤情况 : Metadata Extension:

@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Attendance'
@Metadata.allowExtensions: true
define view entity YST_ATTENDANCE_I
  as select from yst_attendance
  association to parent YSTUDENT_HDR_I as _hdr      on $projection.sid = _hdr.sid
  association to YI_COURSE             as _course   on $projection.course = _course.Value
  association to YI_SEMESTER           as _semester on $projection.semester = _semester.Value
  association to YI_SEMSTAT            as _stat     on $projection.status = _stat.Value
{
  key sid,
  key course,
  key semester,
      _course.Description   as course_desc,
      _semester.Description as semester_desc,
      status,
      _stat.Description     as semester_status,
      percentage,
      feedback,
      _hdr // Make association public
}

元数据扩展 :学籍资料 : 学籍资料

@Metadata.layer: #CORE
@UI: {
    headerInfo: { typeName: 'Attendance Detail',
                  typeNamePlural: 'Attendance Details',
                 
                  title: { type: #STANDARD, label: 'Attendance Detail', value: 'course' },
                  description:{ type: #STANDARD , label: 'Attendance Details' , value : 'course_desc'}

    },
    presentationVariant: [{ sortOrder: [{by: 'semester', direction: #ASC}]  }]


}
@Search.searchable: true
annotate view YST_ATTENDANCE_I
    with 
{
      @UI.facet: [{ id: 'Attendance',
                  purpose: #STANDARD,
                  type: #IDENTIFICATION_REFERENCE,
                  label: 'Attendance Details',
                  position: 10
     }]
  @UI: { identification: [{ position: 10, label: 'Student ID' }] }
  @UI.hidden: true
  sid;
  @UI: { lineItem:       [{ position: 20, importance: #HIGH, label: 'Course' }],
   identification: [{ position: 20, label: 'Course' }] }
  @Search.defaultSearchElement: true
  @Consumption.valueHelpDefinition: [{ entity:
  {name: 'YI_COURSE' , element: 'Value' },
  additionalBinding: [{ localElement: 'course_desc', element: 'Description' }]
  }]
  course;
  @UI: { lineItem:       [{ position: 30, importance: #HIGH, label: '' }],
      identification: [{ position: 30, label: '' }] }
  @Search.defaultSearchElement: true
  course_desc;
  @UI: { lineItem:       [{ position: 40, importance: #HIGH, label: 'Semester' }],
      identification: [{ position: 40, label: 'Semester' }] }
  @Search.defaultSearchElement: true
  @Consumption.valueHelpDefinition: [{ entity:
  {name: 'YI_SEMESTER' , element: 'Value' },
  additionalBinding: [{ localElement: 'semester_desc', element: 'Description' }]
  }]
  semester;
  @UI: { lineItem:       [{ position: 50, importance: #HIGH, label: '' }],
      identification: [{ position: 50, label: '' }] }
  @Search.defaultSearchElement: true
  semester_desc;
  @UI: { lineItem:       [{ position: 60, importance: #HIGH, label: 'Status' }],
  identification: [{ position: 60, label: 'Status' }] }
  @Search.defaultSearchElement: true
  @Consumption.valueHelpDefinition: [{ entity:
  {name: 'YI_SEMSTAT' , element: 'Value' },
  additionalBinding: [{ localElement: 'semester_status', element: 'Description' }]
  }]
  status;
  @UI: { lineItem:       [{ position: 70, importance: #HIGH, label: '' }],
   identification: [{ position: 70, label: '' }] }
  @Search.defaultSearchElement: true
  semester_status;
  @UI: { lineItem:       [{ position: 80, importance: #HIGH, label: 'Percentage Scored' }],
  identification: [{ position: 80, label: 'Percentage Scored' }] }
  @Search.defaultSearchElement: true
  percentage;
  @UI: { lineItem:       [{ position: 90, importance: #HIGH, label: 'Student Feed Back' }],
   identification: [{ position: 90, label: 'Student Feed Back' }] }
  @Search.defaultSearchElement: true
  feedback;
    
}

少数其他用于搜索帮助的CDS。

血型。

@AbapCatalog.sqlViewName: 'YIBG'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Gender'
define view YI_BG as select from DDCDS_CUSTOMER_DOMAIN_VALUE_T( p_domain_name: 'YBG' )
{
key domain_name,
  key value_position,
      @Semantics.language: true
  key language,
      value_low as Value,
      @Semantics.text: true
      text      as Description
    
}

领域 :

课程。

@AbapCatalog.sqlViewName: 'YICOURSE'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Course'
define view YI_COURSE
  as select from DDCDS_CUSTOMER_DOMAIN_VALUE_T( p_domain_name: 'YCOURSE' )
{
  key domain_name,
  key value_position,
      @Semantics.language: true
  key language,
      value_low as Value,
      @Semantics.text: true
      text      as Description

}

域:域名。

性别。

@AbapCatalog.sqlViewName: 'YGEN'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Gender'
define view YI_GENDER as select from DDCDS_CUSTOMER_DOMAIN_VALUE_T( p_domain_name: 'YGENDER' )
{
key domain_name,
  key value_position,
      @Semantics.language: true
  key language,
      value_low as Value,
      @Semantics.text: true
      text      as Description
    
}

范畴 : 医学领域 :

学期。

@AbapCatalog.sqlViewName: 'YISEM'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Semester'
define view YI_SEMESTER
  as select from DDCDS_CUSTOMER_DOMAIN_VALUE_T( p_domain_name: 'YSEMESTER' )
{
  key domain_name,
  key value_position,
      @Semantics.language: true
  key language,
      value_low as Value,
      @Semantics.text: true
      text      as Description

}

范畴 : 硕士

状况 :

@AbapCatalog.sqlViewName: 'YISTAT'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Status'
define view YI_SEMSTAT
  as select from DDCDS_CUSTOMER_DOMAIN_VALUE_T( p_domain_name: 'YSEMSTAT' )
{
  key domain_name,
  key value_position,
      @Semantics.language: true
  key language,
      value_low as Value,
      @Semantics.text: true
      text      as Description

}

领域 : 状况 :

行为定义

managed implementation in class YST_BEHAVIOUR unique;
strict;
define behavior for YSTUDENT_HDR_I 
persistent table ystudent_hdr
lock master
authorization master ( instance )

{
  field ( numbering : managed, readonly ) sid;
  create;
  update;
  delete;
  field ( readonly ) genderdesc;
  field ( readonly ) bg_desc;
  association _attendance { create; }
  association _academic { create; }
}

define behavior for YST_ATTENDANCE_I 
persistent table yst_attendance
lock dependent by _hdr
authorization dependent by _hdr

{
  update;
  delete;
  field ( readonly ) sid;
  field ( readonly ) course_desc;
  field ( readonly ) semester_desc;
  field ( readonly ) semester_status;
  association _hdr;
}

define behavior for YST_CRACADEMIC_I 
persistent table yst_cracademic
lock dependent by _HDR
authorization dependent by _HDR

{
  update;
  delete;
  field ( readonly ) sid;
  field ( readonly ) course_desc;
  field ( readonly ) semester_desc;
  field ( readonly ) semester_status;
  association _HDR;
}

行为的实施。

****Global Class ************
CLASS yst_behaviour DEFINITION
  PUBLIC
  abstract
  final
  for behavior of YSTUDENT_HDR_I .

  PUBLIC SECTION.
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.



CLASS yst_behaviour IMPLEMENTATION.
ENDCLASS.
****Local Types******

CLASS YST_behaviour2 DEFINITION INHERITING FROM cl_abap_behavior_handler.
  PRIVATE SECTION.

    METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION
      IMPORTING keys REQUEST requested_authorizations FOR ystudent_hdr_i RESULT result.


ENDCLASS.

CLASS YST_behaviour2 IMPLEMENTATION.
  METHOD get_instance_authorizations.
********Your code goes here
  ENDMETHOD.
ENDCLASS.

如果我们看一下这里的行为类,我们几乎没有写28行代码,如果我们在一个服务定义中暴露CDS并创建一个服务绑定,所有的父子的CRUD操作都可以正常工作。所有的CRUD操作代码都被系统照顾到了,我们只需付出最小的努力。

由于SAP推荐在CDS中使用视图实体,我们必须创建这个类,如果我们只使用视图,这个类是可选的。

让我们看一下屏幕。

注:该博客是基于我对BTP的研究和发展而写的,如果我提到任何遗漏的信息,请在评论中纠正我。