模型定义在数据库中的映射

模型定义在数据库中的映射

Oinone中通过定义模型来建立数据表,使用注解的方式来使多张表之间的关联。

  1. 数据库字段与模型定义字段映射

    模型定义在数据库中的映射

    package pro.shushi.pamirs.top.api.model;
    
    import pro.shushi.pamirs.core.common.enmu.DataStatusEnum;
    import pro.shushi.pamirs.meta.annotation.Field;
    import pro.shushi.pamirs.meta.annotation.Model;
    import pro.shushi.pamirs.meta.base.IdModel;
    import pro.shushi.pamirs.meta.enmu.DateFormatEnum;
    import pro.shushi.pamirs.meta.enmu.DateTypeEnum;
    import pro.shushi.pamirs.meta.enmu.MimeTypeEnum;
    
    import java.math.BigDecimal;
    import java.util.Date;
    
    @Model.model(PamirsDemo.MODEL_MODEL)
    @Model(displayName = "PamirsDemo")
    public class PamirsDemo extends IdModel {
    
       public static final String MODEL_MODEL = "top.PamirsDemo";
    
       @Field.Binary(mime = MimeTypeEnum.html)
       @Field(displayName = "二进制类型")
       private Byte[] byteType;
    
       @Field.Integer
       @Field(displayName = "整数")
       private Long longType;
    
       @Field.Float
       @Field(displayName = "浮点数")
       private BigDecimal floatType;
    
       @Field.Boolean
       @Field(displayName = "布尔类型")
       private Boolean booleanType;
    
       @Field.Enum
       @Field(displayName = "枚举")
       private DataStatusEnum enumType;
    
       @Field.String
       @Field(displayName = "字符串")
       private String stringType;
    
       @Field.Text
       @Field(displayName = "多行文本")
       private String textType;
    
       @Field.Html
       @Field(displayName = "富文本")
       private String richText;
    
       @Field.Date(type = DateTypeEnum.DATE, format = DateFormatEnum.DATE)
       @Field(displayName = "日期类型")
       private Date dataType;
    
       @Field.Date(type = DateTypeEnum.DATETIME, format = DateFormatEnum.DATETIME)
       @Field(displayName = "日期时间类型")
       private Date dataTimeType;
    
       @Field.Money
       @Field(displayName = "金额")
       private BigDecimal amount;
    }
    

    更多字段基础请参考文档字段基础与复合

  2. 多对一的关系映射

    例:设计一张教师表,一张科目表,教师表对科目表属于多对一的关系,在教师表中使用科目id管理关联关系。

    教师表teacher

    模型定义在数据库中的映射

    科目表professional

    模型定义在数据库中的映射


    那么在Oinone的模型定义中,这两张表定义是这样的;

    教师模型

    package pro.shushi.pamirs.top.api.model;
    
    import pro.shushi.pamirs.meta.annotation.Field;
    import pro.shushi.pamirs.meta.annotation.Model;
    import pro.shushi.pamirs.meta.base.IdModel;
    
    @Model.model(Teacher.MODEL_MODEL)
    @Model(displayName = "教师", summary = "教师")
    public class Teacher extends IdModel {
    
       public static final String MODEL_MODEL = "top.Teacher";
    
       @Field.String
       @Field(displayName = "教师名字")
       private String teacherName;
    
       @Field.Integer
       @Field(displayName = "科目id")
       private Long professionalId;
    
       @Field(displayName = "关联科目")
       @Field.many2one
       @Field.Relation(relationFields = {"professionalId"},referenceFields = {"id"})
       private Professional professional;
    }
    

    该模型创建的数据库如下:

    模型定义在数据库中的映射

    科目模型

    package pro.shushi.pamirs.top.api.model;
    
    import pro.shushi.pamirs.meta.annotation.Field;
    import pro.shushi.pamirs.meta.annotation.Model;
    import pro.shushi.pamirs.meta.base.IdModel;
    
    import java.util.List;
    
    @Model.model(Professional.MODEL_MODEL)
    @Model(displayName = "科目", summary = "科目")
    public class Professional extends IdModel {
    
       public static final String MODEL_MODEL = "top.Professional";
    
       @Field.String
       @Field(displayName = "科目名称")
       private String professionalName;
    
    }

    该模型创建的数据库如下:

    模型定义在数据库中的映射

    使用@Field.many2one注解管理教师与科目的多对一关系,在表操作时会自动维护关联关系。如果业务上是一对一的关系,在模型定义中建议使用多对一进行关联。

  3. 一对多的关系映射

    例:设计一张学生表,一张科目表,学生表对科目表属于一对多的关系,在科目表里使用学生ID与学生表进行关联。

    学生表student
    模型定义在数据库中的映射
    科目表professional
    模型定义在数据库中的映射


    那么在Oinone的模型定义中,这两张表定义是这样的;
    学生模型

    package pro.shushi.pamirs.top.api.model;
    import pro.shushi.pamirs.meta.annotation.Field;
    import pro.shushi.pamirs.meta.annotation.Model;
    import pro.shushi.pamirs.meta.base.IdModel;
    @Model.model(Student.MODEL_MODEL)
    @Model(displayName = "学生", summary = "学生")
    public class Student extends IdModel {
    
        public static final String MODEL_MODEL = "top.Student";
    
        @Field(displayName = "学生名字")
        @Field.String
        private String studentName;
    
        @Field(displayName = "学生ID")
        @Field.Integer
        private Long studentId;
    }
    

    该模型创建的数据库如下:
    模型定义在数据库中的映射

    科目模型

     package pro.shushi.pamirs.top.api.model;
    
     import pro.shushi.pamirs.meta.annotation.Field;
     import pro.shushi.pamirs.meta.annotation.Model;
     import pro.shushi.pamirs.meta.base.IdModel;
    
     import java.util.List;
    
     @Model.model(Professional.MODEL_MODEL)
     @Model(displayName = "科目", summary = "科目")
     public class Professional extends IdModel {
    
     public static final String MODEL_MODEL = "top.Professional";
    
         @Field.String
        @Field(displayName = "科目名称")
        private String professionalName;
    
        @Field(displayName = "关联学生")
        @Field.one2many
        @Field.Relation(relationFields = {"id"},referenceFields = {"studentId"})
        private List<Student> studentList;
    }

    在科目模型中建立@Field.one2many来管理学生和科目的关联关系。该模型创建的数据库如下:
    模型定义在数据库中的映射

  4. 多对多关系的关系映射

    例:设计一张教师表,一张学生表,教师表对学生表属于多对多的关系,使用中间表管理教师和学生的关联关系。

    教师表teacher

    模型定义在数据库中的映射

    学生表student

    模型定义在数据库中的映射

    教师学生中间表teacher_rel_student

    模型定义在数据库中的映射


    那么在Oinone的模型定义中,多对多关系是这样定义的;

    教师模型

    package pro.shushi.pamirs.top.api.model;
    
    import pro.shushi.pamirs.meta.annotation.Field;
    import pro.shushi.pamirs.meta.annotation.Model;
    import pro.shushi.pamirs.meta.base.IdModel;
    
    import java.util.List;
    
    @Model.model(Teacher.MODEL_MODEL)
    @Model(displayName = "教师", summary = "教师")
    public class Teacher extends IdModel {
    
       public static final String MODEL_MODEL = "top.Teacher";
    
       @Field.String
       @Field(displayName = "教师名字")
       private String teacherName;
    
       @Field(displayName = "教师关联学生")
       @Field.many2many(through = TeacherRelStudent.MODEL_MODEL, relationFields = {"teacherId"}, referenceFields = {"studentId"})
       @Field.Relation(relationFields = {"id"}, referenceFields = {"id"})
       private List<Student> studentList;
    }

    该模型创建的数据库如下:

    模型定义在数据库中的映射

    学生模型

    package pro.shushi.pamirs.top.api.model;
    
    import pro.shushi.pamirs.meta.annotation.Field;
    import pro.shushi.pamirs.meta.annotation.Model;
    import pro.shushi.pamirs.meta.base.IdModel;
    
    @Model.model(Student.MODEL_MODEL)
    @Model(displayName = "学生", summary = "学生")
    public class Student extends IdModel {
    
       public static final String MODEL_MODEL = "top.Student";
    
       @Field(displayName = "学生名字")
       @Field.String
       private String studentName;
    }

    该模型创建的数据库如下:

    模型定义在数据库中的映射

    教师学生关系模型

    package pro.shushi.pamirs.top.api.model;
    
    import pro.shushi.pamirs.meta.annotation.Field;
    import pro.shushi.pamirs.meta.annotation.Model;
    import pro.shushi.pamirs.meta.base.BaseRelation;
    
    @Model.model(TeacherRelStudent.MODEL_MODEL)
    @Model(displayName = "教师学生关系表", summary = "教师学生关系表")
    public class TeacherRelStudent extends BaseRelation {
    
       public static final String MODEL_MODEL = "top.TeacherRelStudent";
    
       @Field.Integer
       @Field(displayName = "教师ID")
       private Long teacherId;
    
       @Field.Integer
       @Field(displayName = "学生ID")
       private Long studentId;
    }

    该模型创建的数据库如下:

    模型定义在数据库中的映射

    使用@Field.many2many注解以及中间管理关联关系,在表操作时自动维护关联关系。

Oinone社区 作者:yexiu原创文章,如若转载,请注明出处:https://doc.oinone.top/dai-ma-shi-jian/16109.html

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

(1)
yexiuyexiu
上一篇 2024年8月16日 pm4:24
下一篇 2024年8月17日 pm3:50

相关推荐

  • 如何选择适合的模型类型?

    介绍 通过Oinone 7天从入门到精通的模型的类型章节我们可以知道模型有抽象模型、存储模型、代理模型、传输模型这四种。但是在在定义模型的时候我们可能不知道该如何选择类型,下面结合业务场景为大家讲解几种模型的典型使用场景。 抽象模型 抽象模型往往是提供公共能力和字段的模型,它本身不会直接用于构建协议和基础设施(如表结构等)。 场景:猫、鸟都继承自动物这个抽象模型 package pro.shushi.pamirs.demo.api.model; import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Model; import pro.shushi.pamirs.meta.annotation.sys.Base; import pro.shushi.pamirs.meta.base.IdModel; import pro.shushi.pamirs.meta.enmu.ModelTypeEnum; @Base @Model.model(AbstractAnimal.MODEL_MODEL) @Model.Advanced(type = ModelTypeEnum.ABSTRACT) @Model(displayName = "动物") public abstract class AbstractAnimal extends IdModel { public static final String MODEL_MODEL = "demo.AbstractAnimal"; @Field.String @Field(displayName = "名称") private String name; @Field.String @Field(displayName = "颜色") private String color; } package pro.shushi.pamirs.demo.api.model; import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Model; @Model.model(Cat.MODEL_MODEL) @Model(displayName = "猫") public class Cat extends AbstractAnimal { private static final long serialVersionUID = -5104390780952634397L; public static final String MODEL_MODEL = "demo.Cat"; @Field.Integer @Field(displayName = "尾巴长度") private Integer tailLength; } package pro.shushi.pamirs.demo.api.model; import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Model; @Model.model(Bird.MODEL_MODEL) @Model(displayName = "鸟") public class Bird extends AbstractAnimal { private static final long serialVersionUID = -5144390780952634397L; public static final String MODEL_MODEL = "demo.Bird"; @Field.Integer @Field(displayName = "翼展宽度") private Integer wingSpanWidth; } 存储模型 存储模型用于定义数据表结构和数据的增删改查(数据管理器)功能,是直接与连接器进行交互的数据容器。 场景:存储模型对应传统开发模式中的数据表,上面例子中的Cat和Birdd都属于传输模型,由于模型定义的注解@Model.Advanced(type = ModelTypeEnum.STORE)默认值就是存储模型,所以一般不用手动指定 代理模型 代理模型是用于代理存储模型的数据管理器能力,同时又可以扩展出非存储数据信息的交互功能的模型。 场景一:隔离数据权限 场景二:增强列表的搜索项 场景三:导入导出的时候增加其他特殊信息 场景四:重写下拉组件的查询逻辑做数据过滤 传输模型 传输模型不会在数据库生成的表,只是作为数据的传输使用,跟传统开发模式中的DTO有一点相似。 场景一:批量处理数据 场景二:处理一些跟数据表无关的操作,如:清理指定业务的缓存、查看一些系统监控信息,可以根据业务信息建立对应的传输模型,在传输模型上创建action动作 场景三:通过传输模型完成复杂页面数据传输

    2024年4月7日
    00
  • 如何删除系统权限中默认的首页节点

    场景: 并没有设置过首页的配置,为什么在系统权限这里的配置菜单中却有首页的配置。而且显示当前资源未完成初始化设置,无法配置。这个文章将帮助你删除这个节点。 注意:如果添加了以下代码,后续如果需要使用首页的配置,则需要删除该代码。 扩展权限加载节点: 遍历权限加载的节点,找到需要删除的模块首页节点。删除节点。 @Component @Order(88) @SPI.Service public class MyTestNodeLoadExtend implements PermissionNodeLoadExtendApi { @Override public List<PermissionNode> buildRootPermissions(PermissionLoadContext loadContext, List<PermissionNode> nodes) { //删除 TopModule.MODULE_MODULE 的首页节点。 String homepage = TranslateUtils.translateValues(PermissionNodeLoaderConstants.HOMEPAGE_DISPLAY_VALUE); for (PermissionNode node : nodes) { //如果需要删除多个模块的首页,在这里多加一个逻辑与条件即可。 if (!(node instanceof ModulePermissionNode) || !TopModule.MODULE_MODULE.equals(((ModulePermissionNode) node).getModule())) { continue; } List<PermissionNode> permissionNodes = node.getNodes(); Iterator<PermissionNode> iterator = permissionNodes.iterator(); while (iterator.hasNext()) { PermissionNode permissionNode = iterator.next(); if (ResourcePermissionSubtypeEnum.HOMEPAGE.equals(permissionNode.getNodeType()) && homepage.equals(permissionNode.getDisplayValue())) { iterator.remove(); //如果是删除多个模块首页,这里的return改为break; return nodes; } } } return nodes; } } 看效果:首页节点成功删除。

    2024年12月31日
    00
  • 推送自定义消息

    项目中添加消息依赖 pro.shushi.pamirs.core pamirs-message-api 调用pro.shushi.pamirs.message.engine.message.MessageSender#sendSystemMail发送系统消息示例: @Action(displayName = "发送消息") public Student sendMessage(Student data){ MessageSender mailSender = (MessageSender) MessageEngine.get(MessageEngineTypeEnum.MAIL_SEND).get(null); String content = "发送自定义消息"; String subject = null; List<Long> userIds = new ArrayList<>(); userIds.add(PamirsSession.getUserId()); PamirsMessage message = new PamirsMessage() .setName(subject) .setSubject(subject) .setBody(content) .setMessageType(MessageTypeEnum.NOTIFICATION); List<PamirsMessage> messages = new ArrayList<>(); messages.add(message); SystemMessage systemMessage = new SystemMessage(); systemMessage.setPartners(userIds.stream().map(i -> (PamirsUser) new PamirsUser().setId(i)).collect(Collectors.toList())) .setType(MessageGroupTypeEnum.SYSTEM_MAIL) .setMessages(messages); mailSender.sendSystemMail(systemMessage); return data; }

    2024年8月19日
    00
  • 如何扩展行为权限

    注意:5.2.8 以上版本适用 需求 我们的权限控制需要在页面上有交互才可以在管理中心控制该动作权限,在没有页面交互的动作是不能进行授权操作的。所以本文章将介绍如何将页面上没有交互的动作接入到系统权限中管理。 一、扩展系统权限的菜单页面 实现 步骤: 创建授权节点实现权限节点扩展接口:pro.shushi.pamirs.auth.api.extend.load.PermissionNodeLoadExtendApi#buildRootPermissions @Component @Order(88) public class MyTestNodeLoadExtend implements PermissionNodeLoadExtendApi { public static final String MODEL = AuthTest.MODEL_MODEL; public static final String MODULE = TopModule.MODULE_MODULE; public static final String FUN = "dataStatus"; @Override public List<PermissionNode> buildRootPermissions(PermissionLoadContext loadContext, List<PermissionNode> nodes) { //创建授权根节点 PermissionNode root = createMyNode(); List<PermissionNode> newNodes = new ArrayList<>(); //从缓存中读取需要授权的Action Action cacheAction = PamirsSession.getContext().getExtendCache(ActionCacheApi.class).get(MODEL, FUN); if (cacheAction != null) { //将该Action放入权限树 //权限鉴权的path路径是根据【cacheAction.getModel() + cacheAction.getName()】拼接的。和MODULE没有关系,这里MODULE可以自定义。 AuthNodeHelper.addNode(newNodes, root, AuthNodeHelper.createActionNode(MODULE, cacheAction, root)); } nodes.add(0, root); return newNodes; } private PermissionNode createMyNode() { return AuthNodeHelper.createNodeWithTranslate("MyNode", "自定义节点"); } } 在管理中心中我们可以看到代码里创建的授权节点。 给角色分配该动作的权限,调用我们配置的AuthTest模型的dataStatus动作看效果。 二、扩展菜单下的动作权限 实现 步骤: 创建viewAction用于作为权限菜单"permissionExtension"是自定义的viewAction的name,用于下面拼path路径鉴权。因为这里只需要在系统权限那边利用这个viewAction创建出授权节点。所以”权限扩展form“可以随意定义名字,系统会拿默认视图。 @Model.model(AuthTest.MODEL_MODEL) @Component @UxRouteButton( action = @UxAction(name = "permissionExtension", displayName = "权限扩展", label = "权限扩展", contextType = ActionContextTypeEnum.CONTEXT_FREE), value = @UxRoute(model = AuthTest.MODEL_MODEL, viewName = "权限扩展form", openType = ActionTargetEnum.ROUTER)) public class AuthTestAction { @Action(displayName = "启用", contextType = ActionContextTypeEnum.SINGLE) public AuthTest dataStatus(AuthTest data) { data.setOrgName("给个值"); return data; } } 创建授权节点实现权限节点扩展接口:pro.shushi.pamirs.auth.api.extend.load.PermissionNodeLoadExtendApi#buildRootPermissions @Component @Order(88) public class MyTestNodeLoadExtend implements PermissionNodeLoadExtendApi { //创建授权根节点 @Override public List<PermissionNode> buildRootPermissions(PermissionLoadContext loadContext, List<PermissionNode> nodes) { PermissionNode root = AuthNodeHelper.createNodeWithTranslate("CustomNode", "自定义节点"); List<PermissionNode> newNodes = new ArrayList<>(); newNodes.add(root); ViewAction viewAction = new ViewAction().setModel(AuthTest.MODEL_MODEL).setName("permissionExtension").queryOne(); //将该Action放入权限树 //权限鉴权的path路径是根据【viewAction.getModel(),…

    2024年11月1日
    00
  • mybatis拦截器的使用

    场景:自定义拦截器做数据的加解密。 注册自定义拦截器 @Configuration public class MyBatisConfig { // TODO: 注册自定义拦截器 @Bean @Order(999) public EncryptionInterceptor encryptionInterceptor() { return new EncryptionInterceptor(); } } 使用mybatis拦截器拦截查询。 @Intercepts({ @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}), @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}) }) public class EncryptionInterceptor implements Interceptor { @Autowired private EncryptionConfig encryptionConfig; @Override public Object intercept(Invocation invocation) throws Throwable { Object[] args = invocation.getArgs(); MappedStatement ms = (MappedStatement) args[0]; Object parameter = args[1]; // 判断操作类型是insert, update 或 delete if (ms.getSqlCommandType().equals(SqlCommandType.INSERT) || ms.getSqlCommandType().equals(SqlCommandType.UPDATE) || ms.getSqlCommandType().equals(SqlCommandType.DELETE)) { // TODO: 加密字段 encryptFields(parameter); } else if (ms.getSqlCommandType().equals(SqlCommandType.SELECT)) { // TODO: 查询操作,在执行后需要对结果进行解密 Object result = invocation.proceed(); List<EncryptionConfig.Models> models = encryptionConfig.getModels(); for (EncryptionConfig.Models model : models) { if (judgmentModel(parameter, model)) { decryptFields(result); } } return result; } return invocation.proceed(); } private Boolean judgmentModel(Object parameter, EncryptionConfig.Models model) { MetaObject metaObject = SystemMetaObject.forObject(parameter); if (metaObject.getOriginalObject() instanceof MapperMethod.ParamMap) { if (metaObject.hasGetter("ew")) { Object param1 = metaObject.getValue("ew"); if (param1 != null) { Object originalObject = SystemMetaObject.forObject(param1).getOriginalObject(); if (originalObject instanceof QueryWrapper) { DataMap entity = (DataMap) ((QueryWrapper<?>) originalObject).getEntity(); if (entity != null) { Object modelFieldName = entity.get(FieldConstants._d_modelFieldName);…

    2024年12月2日
    00

Leave a Reply

登录后才能评论