V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
cMoon
V2EX  ›  Java

mybatisplus @TableName 注解中 excludeProperty 赋值问题

  •  
  •   cMoon · 125 天前 · 1065 次点击
    这是一个创建于 125 天前的主题,其中的信息可能已经有所发展或是发生改变。

    想通过 excludeProperty 来排除父类中的字段,但是不想硬编码写死,就写了个静态方法获取父类中的所有字段名, excludeProperty 通过调用这个静态方法赋值,但是提示 Attribute value must be constant.

    百度后了解到注解中属性的赋值只能是常量,这里有没有什么曲线救国的方法,比如使用 SpEL 表达式之类的(SpEL 不太会用,编译虽然能过但没有正确排除父类字段,不清楚是语法错了还是本身就不能解决这个问题),还是说已经是死局了只能硬编码.

    13 条回复    2023-11-01 11:24:57 +08:00
    Jrue0011
        1
    Jrue0011  
       125 天前
    可以是可以...

    一种方式是改 Mybatis-Plus 的 TableInfoHelper 代码实现对 excludeProperty 中 SPEL 的支持,并想办法让所有依赖 TableInfoHelper 的地方能用上新的实现(改源码重新打包、运行时动态增强/替换之类的)

    另一种方式是既然你需求都是静态的,那甚至没必要用 SPEL ,自己写个类似 lombok 的注解处理器修改 excludeProperty
    cMoon
        2
    cMoon  
    OP
       125 天前
    @Jrue0011 #1 要自己实现的话就算了,为了一碟醋包一盘饺子😂 实在没办法我就老老实实写 sql 了
    RedBeanIce
        3
    RedBeanIce  
       125 天前
    我不理解,,请问你可以再描述一下你的根本问题呢,请不要问 AB 问题。
    因为 A 问题,问了 B 问题。

    @tableName 描述的就是数据库的一个单表,为什么会存在父类的情况呢。
    除非是公共字段,,,但是公共字段就是每张表都存在的。
    cMoon
        4
    cMoon  
    OP
       125 天前
    @RedBeanIce #3
    目前有 3 张表 a,b,c
    a 是主表, b,c 可以看成是 a 表的扩充字段.部分情况下 a 表的字段就够了,部分情况需要用到 b 或者 c 的字段.( b,c 都需要和 a 关联查询,不会查单表)
    我想着用同一个实体接收数据的话无用的字段太多,就把 b,c 的实体类继承了 a.
    这样就可以直接用 b,c 的实体类接收数据.

    我也没啥设计经验,前两天本就想发帖问问的,但尝试做了下之后除了不能使用 mp 默认提供的方法也没发现啥弊端就继续这样做了
    win301
        5
    win301  
       125 天前
    绝大部分开发者不会用你这个思路来使用 ORM 框架,所以也不会碰到你的问题
    说个正常的或者通常情况下使用 ORM 框架的思路
    给这 3 个表分别建立 3 个 entity ,3 个 mapper ,然后你再任意 serviceImpl 类里,随意封装数据结构即可
    就是有几百个表都有你说的情况,也都按照这个模式来做,这样即便某些表修改了字段增删了字段,在代码层面的改动会非常小,也很容易改
    cMoon
        6
    cMoon  
    OP
       125 天前
    @win301 #5
    我只是在这基础上多了继承关系,这样在增删改查的时候可以少一步拆分或组装实体类的步骤
    至于增删了字段,相比原来的模式也就多了需要改动插入和更新语句

    这是我目前的理解,我认为还是利大于弊的
    dadebucuo
        7
    dadebucuo  
       125 天前
    不建议对 entity 进行继承操作, 可以定义公共字段的 get, set 方法作为接口, 子类来实现
    wolfie
        8
    wolfie  
       125 天前 via Android
    bytebuddy 运行时重新定义。

    公共的数据库实体父类,就应该在父类主动 exclude 。
    DreamSpace
        9
    DreamSpace  
       125 天前 via Android
    @cMoon 能明白 op 的意思,我提一点个人看法。
    其实你的 B 实体看似和 A 相似,但却有不同的业务意义,这时他们就是两个独立的实体,并不具有继承关系。
    比如用于页面显示的 VO 和数据库层的 DO ,DO 中的 createTime 是 Date 类型,在 VO 中却是个 formatString 。
    DO 不出 service ,VO 不进 dao ,实体变换/组装在 service 或者构造器中完成,嫌麻烦也可以用 mapstruct 之类的工具辅助。
    DreamSpace
        10
    DreamSpace  
       125 天前 via Android
    关于主楼提到的问题,注解和普通的 property 是一类东西,编译后就已经固定下来了,但你写的静态方法是必须运行时才会执行的,所以只能硬编码。回到硬编码的话,直接复制父类的属性贴在子类上然后打注解也许更快。
    win301
        11
    win301  
       125 天前
    @cMoon 你这相当于是面向数据库编程了,这 b 表和 c 表如果以后还会被其他表关联,你打算怎么做?继续通过继承,然后继续 excludeProperty 无关字段?(假设 excludeProperty 能实现你的想法),建议你复习一下或者重新学习一下面向对象编程有五个基本原则。
    cMoon
        12
    cMoon  
    OP
       125 天前
    @win301 #11
    b ,c 是 a 的扩充字段不会关联其他表,但 a 可能会继续关联新的 d ,e 表

    @DreamSpace #9
    我就用优惠券举个例子吧
    表 a 是通用的优惠券表,包含优惠金额,有效期限等
    表 b ,c 是特殊的优惠券表,像某些券会指定哪些商家可以用,就会拓展一些可用商家 id 的字段

    a ,b ,c 本质都是优惠券,只不过 a 没有额外字段的需求,能满足大部分优惠券的场景,b ,c 是为了剩下一小部分的场景做了单独的处理。
    b ,c 显式地继承了 a ,也可以认为 a 继承了 a 本身,a 不仅是一个实体,也作为了一层抽象。

    优惠券新增方法的参数声明可以声明成 a ,这样传参也能传入 b ,c 的实体类,之后就可以根据实际类型去处理不同的业务

    直接复制父类的属性贴在子类上然后打注解也许更快。 --- 如果没有更好的方法了我是准备这么做了
    Aresxue
        13
    Aresxue  
       124 天前
    瞄了眼源码,除非改源码实现不了。

    第一 MP 功能确实不够强大,其实对于 excludeProperty 本来应该是提供 @JsonIgnore 、 @JsonIgnoreParentProperties 这样单独的注解去实现的,同时还要留给外界一些扩展点类似 jackson 的 BeanSerializerModifier 去做自定义。
    第二虽然知道很多小项目怎么写都可以顺手就行,但是 DO 一把梭随便继承这种坏习惯能避免还是尽量避免,至于为啥不用继承这几乎是一种共识了,耦合度 继承 > 接口 > 组合。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   996 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 19:40 · PVG 03:40 · LAX 11:40 · JFK 14:40
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.