O2M、M2O、M2M关系字段配置问题以及问题排查路径

  1. M2O关系字段

    配置示例:

       @Field(displayName = "教师关联学生")
       @Field.many2one
       @Field.Relation(relationFields = {"studentName"}, referenceFields = {"name"})
       private Student students;

    解析:

    • 在这个多对一关系中,studentName为本模型的字段,name为Student的字段,这个多对一关系通过这两个字段关联起来。
    • 在保存该关联关系时,会将name的值带到studentName里并保存在当前模型中(many)
    • studentName字段必须是存储字段,因为在查询many的数据的时候是通过这个字段进行查询的。
    • name必须在关系模型即Student里面定义(one),studentName在本模型里面定义不定义都可以,如果没有的话会在本模型中创建该字段。

    常见问题:

    • 启动报错:根据报错内容进行相应修改
    • 保存报错:Duplicate entry '******' for key 'PRIMARY',报这个错是因为studentName是唯一键,在将相同name的值赋值给studentName时导致唯一键冲突。其他关系也会有此情况。
  2. O2M关系字段

    配置示例:

       @Field(displayName = "教师关联宠物")
       @Field.one2many
       @Field.Relation(relationFields = {"id"}, referenceFields = {"teacherId"})
       private List<PetShop> studentsCode;

    解析:

    • 在这个一对多关系中,id为本模型的字段,teacherId为PetShop的字段,这个一对多关系通过这两个字段关联起来。
    • 在保存该关联关系时,会将id的值带到teacherId里并保存在PetShop模型中(many)
    • id必须在本模型中定义(one), teacherId在PetShop模型里面定义不定义都可以,如果没有的话会在PetShop模型中创建该字段。

    常见问题:

    • 启动报错:根据报错内容进行相应修改

    • 保存报错:请先保存关联关系模型:如果 id 为自定义字段 与 PetShop进行关联,那么保存关联关系时必须给id 赋值,不然会报错

  3. M2M关系字段

    配置示例1:

    @Field.many2many(through = OrderRelLogistics.MODEL_MODEL, relationFields = {"parentOrderId"}, referenceFields = {"logisticsBillId"})
    @Field.Relation(relationFields = {"id"}, referenceFields = {"id"})
    @Field(displayName = "物流单")
    private List<LogisticsBill> logisticsBillList;

    解析:

    • 在这个多对多关系中,id(左)为本模型的字段,id(右)为PetShop的字段。OrderRelLogistics.MODEL_MODEL为中间表,在保存关联关系时中间表会维护双方的关系字段,id(左)的值写到中间表的parentOrderId字段,id(右)的值写到中间表的logisticsBillId字段。

    常见问题:

    • 保存报错,请先保存关联关系模型:如果id(左)为在本模型自定义的字段,则需要在保存关联关系的时候的时候将该自定义赋值,这样才能正确保存关联关系。

    配置示例2:

    新增TalentTypeEnum

    @Dict(dictionary = TalentTypeEnum.DICTIONARY,displayName = "达人类型")
    public class TalentTypeEnum extends BaseEnum {
    
       public static final String DICTIONARY ="top.TalentTypeEnum";
    
       public final static TalentTypeEnum DOG =create("DOG",1,"狗达人","狗达人");
       public final static TalentTypeEnum CAT =create("CAT",2,"猫达人","猫达人");
    }

    中间表定义

    @Model.model(PetItemRelPetTalent.MODEL_MODEL)
    @Model(displayName = "中间表", summary = "中间表")
    public class PetItemRelPetTalent extends BaseRelation {
    
       public static final String MODEL_MODEL = "top.PetItemRelPetTalent";
    
       @Field.String
       @Field(displayName = "商店ID")
       private String petItemId;
    
       @Field.String
       @Field(displayName = "宠物ID")
       private String petTalentId;
    
       @Field.String
       @Field(displayName = "宠物类型")
       private TalentTypeEnum talentType;
    }

    关系字段定义(关联关系中,使用”##“包括定义常量,这里定义常量"test")

       @Field(displayName = "推荐达人")
       @Field.many2many(
               through = PetItemRelPetTalent.MODEL_MODEL,
               relationFields = {"petItemId"},
               referenceFields = {"petTalentId","talentType"}
       )
       @Field.Relation(relationFields = {"id"}, referenceFields = {"id", "#2#"})
       private List petTalents;

    解析:

    • 在这个多对多的关系中,查询时首先会查当前模型的字段,拿到当前模型的id(左),然后根据条件petItem_id=id(左) 去查中间表,就可以在中间表里查询出多个categoryId,talentType,然后根据条件(id(右), talenttype) IN (categoryId,talentType)查询出关系表PetTalent
    • 注意:talentType字段必须在关系表PetTalent中定义,并和中间表定义的字段talentType保持一致
    • O2M、M2O、M2M关系字段配置问题以及问题排查路径

    常见问题:

    • 报错:需要配置关联模型的关联字段:原因是在PetTalent中没有定义talentType字段

    配置示例3:

       @Field(displayName = "类目")
       @Field.many2many(
               through = MaterialRelCategory.MODEL_MODEL,
               relationFields = {"materialId","type"},
               referenceFields = {"categoryId"}
       )
       @Field.Relation(relationFields = {"id", "#test#"}, referenceFields = {"id"})
       private List categoryList;

    解析:

    • 在这个多对多关系中,查询时首先会查当前模型的字段,拿到当前模型的id(左),然后根据条件material_id=id(左) AND type = test 去查中间表,就可以在中间表里查询出多个categoryId,然后根据条件id(右)IN (categoryId)查询出关系表MaterialCategory
    • O2M、M2O、M2M关系字段配置问题以及问题排查路径
    • 更多使用方式见文档https://doc.oinone.top/oio4/9241.html

Oinone社区 作者:yexiu原创文章,如若转载,请注明出处:https://doc.oinone.top/wen-ti-zhen-duan/15999.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

(1)
yexiuyexiu
上一篇 2024年8月8日 pm12:55
下一篇 2024年8月10日 pm12:59

相关推荐

  • 保存多值字段SQL执行报错

    定义多值类型时,字段类型应该设置为List类型。 @Field.String @Field(displayName ="经费证明", multi = true, serialize = Field.serialize.JSON) private List<String> matchFund; 场景复现

    2024年8月30日
    00
  • 序列化工具使用问题

    后端使用的JSON序列化JsonUtils.toJSONString(nodes);前端使用的JSON序列化PamirsJsonUtils.toJSONString(nodes, SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.WriteDateUseDateFormat, SerializerFeature.BrowserCompatible);注意:用什么工具序列化,就用什么工具反序列化、parse 的时候,要保持一致, 使用PamirsJsonUtils序列化工具主要是为了解决枚举取值错误的问题以及id精度丢失问题。当出现这两个问题的时候,需要使用PamirsJsonUtils 进行序列化。

    2024年9月5日
    00
  • 工作流工作台无权限排查路径

    现象:用户前端自定义跳转工作流审批页面,提示无权限 排查路径: 5.0版本权限是根据路径进行鉴权的,请求载荷中variables需要携带path路径。 示例:path=/management_center/AuthMenus_RoleAndPermission_SystemPermission如果是用户自定义跳转页面,需要配置sessionPath:,值为url中的path路径 查看debug信息中权限上下文中角色携带的权限是否正确 复制debug信息中的path路径,去权限上下文中搜索查看该路径下所有的权限 ~~~ “getRoleActionPermissionsByViewAction:workbench.WorkBenchWorkflowUserTaskActive:WorkflowMenus_WorkBenchMenu_ActiveUserTaskMenu”: { “630732547466232342”: { “/workflow/WorkflowMenus_WorkBenchMenu_ActiveUserTaskMenu/ACTION#workbench.WorkBenchWorkflowUserTaskActive#workflow_write/ACTION#workflow.WorkflowUserTask#workflow_writeturnon”: 1, “/workflow/WorkflowMenus_WorkBenchMenu_ActiveUserTaskMenu/ACTION#workbench.WorkBenchWorkflowUserTaskActive#workflow_wait/ACTION#workflow.WorkflowUserTask#workflow_agree”: 1, } }, ~~~ 参数介绍: 630732547466232342:角色630732547466232342拥有的所有权限信息 /workflow/WorkflowMenus_WorkBenchMenu_ActiveUserTaskMenu:path路径 /ACTION#workbench.WorkBenchWorkflowUserTaskActive#workflow_write:此path路径下面的ACTION,模型为workbench.WorkBenchWorkflowUserTaskActive的workflow_write动作。 对比无权限页面和以上参数是否对应。可在页面url上查看模型,动作。常见问题有模型不匹配(更换为正常有权限的模型)、角色下无动作权限。

    2024年8月6日
    00
  • 调试工具在业务场景的使用-后端

    这篇文档主要介绍在业务场景中,使用调试工具解决后端问题的思路。 调试工具的使用见文档:问题排查调试工具使用手册 调试工具的页面内容介绍:Oinone平台可视化调试工具 例1:模型配置不存在 现象:点击详情报模型配置不存在错误 排查路径: 将报错请求复制到接口调试出,查看调试信息 在调试信息页面,可以看到全部堆栈,利用堆栈信息找报错问题。 可以看到执行了StudentAction的queryOne方法在42行有问题 检查代码发现传进queryList的wrapper参数没有指定模型编码。添加模型编码问题解决 例2:无权限问题排查 现象:用户前端自定义跳转工作流审批页面,提示无权限 排查路径: 将报错请求复制到接口调试处,查看调试信息 查看debug信息中权限上下文中角色携带的权限是否正确。复制debug信息中的path路径,去权限上下文中搜索查看该路径下所有的权限。 根据上面的path路径搜索权限信息: ~~~ "getRoleActionPermissionsByViewAction:workbench.WorkBenchWorkflowUserTaskActive:WorkflowMenus_WorkBenchMenu_ActiveUserTaskMenu": { "630732547466232342": { "/workflow/WorkflowMenus_WorkBenchMenu_ActiveUserTaskMenu/ACTION#workbench.WorkBenchWorkflowUserTaskActive#workflow_write/ACTION#workflow.WorkflowUserTask#workflow_writeturnon": 1, "/workflow/WorkflowMenus_WorkBenchMenu_ActiveUserTaskMenu/ACTION#workbench.WorkBenchWorkflowUserTaskActive#workflow_wait/ACTION#workflow.WorkflowUserTask#workflow_agree": 1, } }, ~~~ 参数介绍: 630732547466232342:角色id为630732547466232342拥有的所有权限信息 /workflow/WorkflowMenus_WorkBenchMenu_ActiveUserTaskMenu:path路径 /ACTION#workbench.WorkBenchWorkflowUserTaskActive#workflow_write:此path路径下面的ACTION,模型为workbench.WorkBenchWorkflowUserTaskActive的workflow_write动作。 对比无权限页面和以上参数是否对应。可在页面url上查看模型,动作。常见问题有模型不匹配(更换为正常有权限的模型)、角色下无动作权限。 经查看调试信息发现,设置的该角色下并无所需动作的权限信息,考虑由于前端自定义跳转页面没有配置sessionPath所致。 由于5.0版本权限是根据路径进行鉴权的,请求载荷中variables需要携带path路径。 如果是用户自定义跳转页面,需要配置sessionPath:/workflow/WorkflowMenus_WorkBenchMenu_ActiveUserTaskMenu,值为url中的path路径。

    2024年9月26日
    00
  • Function、Action函数使用规范

    Function的定义需要严格遵循Oinone的规范, @Action是指页面上有按钮展示的方法,所有@Action注解的方法都是需要在权限处设置权限才能访问的。Action背后都对应一个Function。 @Function是Oinone的可管理的执行逻辑,是无处不在的。 如果只是查询,不需要在页面有按钮,定义为@Function就可以了。 覆写常用默认数据管理器定义标准 @Action.Advanced(name = FunctionConstants.create, managed = true)//默认取的是方法名 @Action(displayName = "确定", summary = "添加", bindingType = ViewTypeEnum.FORM) public AuthRole create(AuthRole data) { @Action.Advanced(type = FunctionTypeEnum.UPDATE, managed = true, invisible = ExpConstants.idValueNotExist) @Action(displayName = "更新", label = "确定", summary = "修改", bindingType = ViewTypeEnum.FORM) public AuthRole update(AuthRole data) { @Action.Advanced(type = FunctionTypeEnum.DELETE, managed = true) @Action(displayName = "删除", label = "删除", contextType = ActionContextTypeEnum.SINGLE_AND_BATCH) @Function.fun(FunctionConstant.deleteWithFieldBatch) public List<AuthRole> delete(List<AuthRoe> dataList) { @Function.Advanced(displayName = "查询角色列表", type = FunctionTypeEnum.QUERY, category = FunctionCategoryEnum.QUERY_PAGE, managed = true) @Function(openLevel = {FunctionOpenEnum.LOCAL, FunctionOpenEnum.REMOTE, FunctionOpenEnum.API}) public Pagination<AuthRole> queryPage(Pagination<AuthRole> page, IWrapper<AuthRole> queryWrapper) {//注意方法名和入参名称必须和平台保持一致 @Function.Advanced(displayName = "查询指定角色", type = FunctionTypeEnum.QUERY, category = FunctionCategoryEnum.QUERY_ONE, managed = true) @Function.fun(FunctionConstants.queryByEntity) @Function(openLevel = {FunctionOpenEnum.LOCAL, FunctionOpenEnum.REMOTE, FunctionOpenEnum.API}) public AuthRole queryOne(AuthRole query) {//注意方法名和入参名称必须和平台保持一致 自定义函数定义标准 @Action(displayName = "启用") @Action.Advanced(type = FunctionTypeEnum.UPDATE) public Teacher dataStatus(Teacher data) { } @Function(displayName = "构造", openLevel = FunctionOpenEnum.API) @Function.Advanced(type = FunctionTypeEnum.QUERY) public Teacher constructAll(Teacher data) { } 注意事项: 覆写常用默认数据管理器Function定义需要严格按照以上函数定义,包括出入参名字定义、注解定义。定义错误会导致gql请求报错或者找不到函数。 定义@Action或者@Function时,函数出入参必须是当前类注解定义的@Model.model()的模型,或者被该模型字段全包含的的模型,比如它的父模型。 页面调用使用的@Action或者@Function方法,出入参必须是oinone的对象,且不能是基础的java类型,因为oinone的对象有元数据信息,这样才能完成前后端之间的自动交互 managed = true定义当前函数为数据管理函数。它只有在重写平台默认数据管理器时需要使用。 @Function.fun()代表定义函数编码,不可更改,默认与方法名称相同。同一个模型Action内不允许有两个相同的函数编码。 不要使用set、get、unset作为函数方法名的开头,不要使用toString作为函数方法名。 传输模型没有默认的数据管理器,所以不能定义数据管理函数。 @Action和@Function注解使用约定 重写内置数据管理器动作和函数的,应与平台注册方式完全保持一致。以下属性可根据需要进行修改:(必须) @Function.Advanced#displayName @Function#openLevel 自定义方法不要与内置数据管理器中定义的动作和函数重名。(必须) @Action和@Function注解不要混合使用。(自定义方法必须) 如无特殊必要,请不要使用如下属性修改函数定义:(自定义方法必须) @Function#name @Function.fun#value @Function.Advanced#managed @Function.Advanced#builtin @Function.Advanced#group @Function.Advanced#version @Action.Advanced#name @Action.Advanced#args @Action.Advanced#managed @Action.Advanced#language 自定义方法在选择注册动作或函数时,应按照如下规则进行判断:(必须) 若该方法通过用户行为触发的,应注册为动作。 若该方法通过“入口”进行控制的,应注册为函数。 自定义方法若注册为动作时,应按照如下规则进行定义: 使用@Action.Advanced#type属性定义函数类型,默认为UPDATE。混合操作的动作应明确列出所有类型。(必须) 使用@Action#displayName属性定义动作功能名称。如无特殊必要,同一模型下的所有动作名称不要重复。页面展示名称重复的,可使用@Action#label属性定义展示名称。(必须)…

    2024年8月20日
    00

Leave a Reply

登录后才能评论