baomidou / mybatis-plus

An powerful enhanced toolkit of MyBatis for simplify development
https://baomidou.com
Apache License 2.0
16.3k stars 4.3k forks source link

有点没理解 TableField fill属性的设计思想 #6120

Closed StephinChou closed 4 months ago

StephinChou commented 4 months ago

请详细描述需要增加的功能 场景很常见,插入或者更新字段时自动填充某些公共字段。

我需要在字段上添加TableField注解

@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;

然后实现一个 MetaObjectHandler 接口,实现具体的填充逻辑。

@Override public void updateFill(MetaObject metaObject) { setFieldValByName("updateUser", 2L, metaObject); }

我的问题是,我在updateFill方法里可以自己决定要修改哪些字段的,那么 @TableField 里的fill字段就很比较奇怪,因为这个注解并不代表 这个字段会被 自动填充, 更像是一个触发自动填充的 触发器? 如果是一个触发器的话,感觉这个属性放在 Table 层次更合理一些?

数据表的 层面先确认这个表在 更新或者插入时 会触发自动填充逻辑, MetaObjectHandler 里则实现具体的填充逻辑。

StephinChou commented 4 months ago

另外,填充逻辑似乎只支持一个类,如果有多种填充逻辑是需要自己在 一个类里进行区分实现吗?

miemieYaho commented 4 months ago

ognl知道吧,ognl得到最终sql之后才会走填充,另外什么一个类八个类的,你要区分什么说清楚

StephinChou commented 4 months ago

ognl知道吧,ognl得到最终sql之后才会走填充,另外什么一个类八个类的,你要区分什么说清楚

要区分的类意思是:

例如针对实体A,我只要填充一个 updateUser 字段 针对实体B,我只要填充一个 updateTime 字段

只能在 handler的 updateFill(MetaObject obj)

if (obj.getOriginalObject() instance of A) {
     setFieldValByName("updateUser", getUser(), metaObject);
} else if (obj.getOriginalObject() instance of A) {
     setFieldValByName("updateTime", new Date(), metaObject);    
}

用这样的写法,而不能在 @TableField 指定我应该使用哪个填充逻辑

miemieYaho commented 4 months ago

就这样的啊,有什么问题?

StephinChou commented 4 months ago

就这样的啊,有什么问题?

就是想确认下有没有更优雅的方案而已。 那这第二个问题结了。

主要还是想确认下这个。

@TableField(fill=INSERT_UPDATE) 我只要在实体类的任意一个字段注解, 然后在handle里写字段注入逻辑就可以了。

所以感觉fill这个属性应该是注解到 Table层面, 而不是字段层面

86jkuncle commented 4 months ago

ognl知道吧,ognl得到最终sql之后才会走填充,另外什么一个类八个类的,你要区分什么说清楚

要区分的类意思是:

例如针对实体A,我只要填充一个 updateUser 字段 针对实体B,我只要填充一个 updateTime 字段

只能在 handler的 updateFill(MetaObject obj)

if (obj.getOriginalObject() instance of A) {
     setFieldValByName("updateUser", getUser(), metaObject);
} else if (obj.getOriginalObject() instance of A) {
     setFieldValByName("updateTime", new Date(), metaObject);    
}if (obj.getOriginalObject() instance of A) { setFieldValByName(“updateUser”, getUser(), metaObject); } else if (obj.getOriginalObject() instance of A) { setFieldValByName(“updateTime”, new Date(), metaObject); }

用这样的写法,而不能在 @TableField 指定我应该使用哪个填充逻辑 请问你的getUser()方法哪来的。。

Fxiao1 commented 2 months ago

请详细描述需要增加的功能 场景很常见,插入或者更新字段时自动填充某些公共字段。

我需要在字段上添加TableField注解

@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;

然后实现一个 MetaObjectHandler 接口,实现具体的填充逻辑。

@OverRide public void updateFill(MetaObject metaObject) { setFieldValByName("updateUser", 2L, metaObject); }

我的问题是,我在updateFill方法里可以自己决定要修改哪些字段的,那么 @TableField 里的fill字段就很比较奇怪,因为这个注解并不代表 这个字段会被 自动填充, 更像是一个触发自动填充的 触发器? 如果是一个触发器的话,感觉这个属性放在 Table 层次更合理一些?

数据表的 层面先确认这个表在 更新或者插入时 会触发自动填充逻辑, MetaObjectHandler 里则实现具体的填充逻辑。

我也有跟你一样的疑惑,所以特地来这里搜索了,我个人认为就应该提供一个类似于@TableField(fill = FieldFill.INSERT,filler="com.zd.Abc"),这样的注解,其中fill表明该属性在什么条件下需要检查是否需要填充,filler表示一个填充器实现类的全类名,填充器接口应该类似于下面这样:

public interface FieldFiller<T> {
    T get();
}

这样,逻辑就通顺了,如果符合条件了,就判断当前属性是否为空,是的话,就调用com.zd.Abc这个实现类的get()方法,将收到的值填充进该属性。


另外现在mybatis-plus的这套好像还有个逻辑问题,比如我createTime和updateTime字段都注册了插入时检查填充,即

    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;

但是我业务上给createTime赋值了,mybatis-plus插入时候检查createTime有值,不需要填充,则不执行com.baomidou.mybatisplus.core.handlers.MetaObjectHandler#insertFill方法,但是继续判断updateTime字段,发现它是空,需要填充,就执行了com.baomidou.mybatisplus.core.handlers.MetaObjectHandler#insertFill,结果就将createTime中的原始值给覆盖了。 因为我为了给这两个属性填充,不得不在insertFill方法中对这两个字段都进行填充操作,即:

@Override
public void insertFill(MetaObject metaObject) {
    Object originalObject = metaObject.getOriginalObject();

    if (originalObject instanceof BaseEntity) {
        Timestamp currentTime = new Timestamp(System.currentTimeMillis());
        this.setFieldValByName("createTime", currentTime, metaObject);
        this.setFieldValByName("updateTime", currentTime, metaObject);
    }
}