Coder Social home page Coder Social logo

babyfish-ct / jimmer Goto Github PK

View Code? Open in Web Editor NEW
630.0 10.0 67.0 29.17 MB

A revolutionary ORM framework for both java and kotlin.

License: Apache License 2.0

Java 83.44% Kotlin 16.36% Shell 0.01% HTML 0.08% ANTLR 0.10%
data immutable immutable-collections immutable-datastructures java fetch jdbc orm draft immer cache redis caffine redis-cache kotlin graphql

jimmer's Introduction

logo

A revolutionary ORM framework for both java and kotlin, and a complete integrated solution

1. Classic ORM part

1.1. Powerful features

feature

1.2. Ultimate performance

performance

2. New ORM part

  1. DTO language
  2. A more comprehensive and powerful caching mechanism, as well as highly automated cache consistency
  3. More powerful client openapi and typescript generation capabilities, including Jimmer's unique remote exceptions
  4. Quickly create GraphQL services
  5. Cross-microservice remote entity associations

Links

English 中文
Examples https://github.com/babyfish-ct/jimmer-examples
Dcoumentation English Documentation 中文文档
Discussion https://discord.gg/PmgR5mpY3E QQ群:622853051

jimmer's People

Contributors

a8t3r avatar aboutzz avatar argonariod avatar asdfgh avatar babyfish-ct avatar belovaf avatar byd-android-2017 avatar chenzhenweiwei avatar clearplume avatar draco1023 avatar enaium avatar flynndi avatar huyaro avatar leeaee avatar leomillon avatar moeshin avatar mtpkiss avatar nanakura avatar qinkangdeid avatar spindensity avatar sunshio avatar tokgoronin avatar wackygem avatar xuejmnet avatar yuki-mirai avatar zhanglolo avatar zhumubo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jimmer's Issues

批量保存(batchSaveCommand)后,获取Entity实体id失败

错误复现代码

val medias = mediaDtos.map { media ->
  new(Media::class).by {
    MediaType.valueOf(media.type)?.let {
      this.type = it
    }
    media.url?.let {
      this.url = it
    }
    this.order = media.order ?: 0
  }
}

val result = sqlClient
  .entities
  .batchSave(medias) {
    setMode(SaveMode.INSERT_ONLY)
  }

result.simpleResults.map {
  it.modifiedEntity.id
}

异常信息

image

附: Media.kt

import com.wonderkids.api.core.enums.MediaType
import org.babyfish.jimmer.sql.*

@Entity
@Table(name = "WK_MEDIA")
interface Media {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  val id: Long

  val type: MediaType

  val url: String

  @Column(name = "`ORDER`")
  val order: Int
}

java.sql.Date 和 java.sql.Time执行toInstant报错

if (value instanceof Date) {
return tryConvertInstant(((Date) value).toInstant(), expectedType);
}

java.sql.Date 和 java.sql.Time 都继承自 java.util.Date,但是都不支持 toInstant 方法,67行会报错。本来想提个PR,但是我的IDEA版本是2019.3,工程都无法编译,就放弃了。就是将二者分别转成 LocalDate 和 LocalTime,再转换成 Instant。

SpringBoot3无法使用

2023-02-25T12:47:59.864+08:00  WARN 27344 --- [           main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: @Configuration class 'SqlClientConfig' contains overloaded @Bean methods with name 'caches'. Use unique method names for separate bean definitions (with individual conditions etc) or switch '@Configuration.enforceUniqueMethods' to 'false'.
Offending resource: class path resource [org/babyfish/jimmer/spring/cfg/SqlClientConfig.class]
2023-02-25T12:47:59.935+08:00  INFO 27344 --- [           main] .s.b.a.l.ConditionEvaluationReportLogger : 

Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2023-02-25T12:47:59.952+08:00 ERROR 27344 --- [           main] o.s.boot.SpringApplication               : Application run failed

org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: @Configuration class 'SqlClientConfig' contains overloaded @Bean methods with name 'caches'. Use unique method names for separate bean definitions (with individual conditions etc) or switch '@Configuration.enforceUniqueMethods' to 'false'.
Offending resource: class path resource [org/babyfish/jimmer/spring/cfg/SqlClientConfig.class]

legacy project support

@babyfish-ct really good staff with brilliant idea, i cannot wait to have a bit on it, when i try it within a legacy project, error comes out, it says org.babyfish.jimmer.apt.meta.MetaException: Illegal class "com.xxx.model.OrderEntity" immutable type must be interface, i know the new "entity" must be interface, but an old-fashion ORM was used, many old class entities use the same JPA annotation mechanisim, and they cannot be reformed at once, so is there any way i can ignore those old entities? so that the oldman could work together with jimmer util his retirement, thank you

[BUG]配置文件中jimmer.show-sql在同时配置EntityManager和JSqlClient的情况下不生效

版本信息

jimmer: 0.6.1
jdk: 19

复现步骤

application.yml配置

jimmer:
  show-sql: true

Jimmer配置类

@Configuration
public class JimmerConfig {

    @Bean
    public ImmutableModule immutableModule() {
        return new ImmutableModule();
    }
    
    @Bean
    public EntityManager entityManager() {
        return JimmerModule.ENTITY_MANAGER;
    }

    @Bean(name = "sqlClient")
    public JSqlClient jSqlClient(DataSource dataSource) {
        return JSqlClient.newBuilder()
                         .setEntityManager(entityManager())
                         .setConnectionManager(new SpringConnectionManager(dataSource))
                         .setDialect(new MySqlDialect())
                         .build();
    }
}

service调用

    public List<OperationLog> findOperationLog() {
        Page<OperationLog> logPage = operationLogRepository.findAll(0, 3);
        List<OperationLog> logList = sqlClient.createQuery(logTable).select(logTable).limit(3, 0).execute();
        return logList;
    }

调用接口后打印的日志

2022-12-30T10:32:21.621+08:00  INFO 6944 --- [nio-8080-exec-2] o.a.c.c.C.[.[localhost].[/jimmer]        : Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-12-30T10:32:21.622+08:00  INFO 6944 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2022-12-30T10:32:21.622+08:00  INFO 6944 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet        : Completed initialization in 0 ms
2022-12-30T10:32:21.675+08:00  INFO 6944 --- [nio-8080-exec-2] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2022-12-30T10:32:21.811+08:00  INFO 6944 --- [nio-8080-exec-2] com.zaxxer.hikari.pool.HikariPool        : HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@1c46458
2022-12-30T10:32:21.813+08:00  INFO 6944 --- [nio-8080-exec-2] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.

可以看到在日志中,不论是调用repository的接口,还是直接用sqlClient调用,都没有打印出sql。

在Jimmer配置类中注释掉JSqlClient的Bean

@Configuration
public class JimmerConfig {

    @Bean
    public ImmutableModule immutableModule() {
        return new ImmutableModule();
    }

    @Bean
    public EntityManager entityManager() {
        return JimmerModule.ENTITY_MANAGER;
    }

//    @Bean(name = "sqlClient")
//    public JSqlClient jSqlClient(DataSource dataSource) {
//        return JSqlClient.newBuilder()
//                         .setEntityManager(entityManager())
//                         .setConnectionManager(new SpringConnectionManager(dataSource))
//                         .setDialect(new MySqlDialect())
//                         .build();
//    }
}

在service调用中注释掉sqlClient的调用,只采用repository的接口

    public List<OperationLog> findOperationLog() {
        Page<OperationLog> logPage = operationLogRepository.findAll(0, 3);
//        List<OperationLog> logList = sqlClient.createQuery(logTable).select(logTable).limit(3, 0).execute();
        return logPage.getContent();
    }

打印的日志

2022-12-30T10:34:18.376+08:00  INFO 20100 --- [nio-8080-exec-1] o.a.c.c.C.[.[localhost].[/jimmer]        : Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-12-30T10:34:18.376+08:00  INFO 20100 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2022-12-30T10:34:18.376+08:00  INFO 20100 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 0 ms
2022-12-30T10:34:18.426+08:00  INFO 20100 --- [nio-8080-exec-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2022-12-30T10:34:18.558+08:00  INFO 20100 --- [nio-8080-exec-1] com.zaxxer.hikari.pool.HikariPool        : HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@1126732
2022-12-30T10:34:18.560+08:00  INFO 20100 --- [nio-8080-exec-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2022-12-30T10:34:18.565+08:00  INFO 20100 --- [nio-8080-exec-1] o.b.jimmer.sql.runtime.ExecutorForLog    : jimmer> sql: select count(tb_1_.ID) from t_operation_log as tb_1_, variables: [], purpose: QUERY
2022-12-30T10:34:18.667+08:00  INFO 20100 --- [nio-8080-exec-1] o.b.jimmer.sql.runtime.ExecutorForLog    : jimmer> sql: select tb_1_.ID, tb_1_.OPERATOR, tb_1_.OPERATION_ACTION, tb_1_.MODULE, tb_1_.OPERATION_IP, tb_1_.OPERATION_RESULT, tb_1_.OPERATION_ARGS, tb_1_.OPERATION_DESCRIPTION, tb_1_.OPERATION_SIZE, tb_1_.OPERATION_START_TIME, tb_1_.OPERATION_END_TIME from t_operation_log as tb_1_ limit ?, variables: [3], purpose: QUERY

可以看到此时才打印了sql

生成ts.zip文件有一些小问题

调用jimmer生成ts.zip接口时,如果是get请求,ts生成的时候,默认的是无参数的。
如:

async list(): Promise<
        List<OrderInfoDto['DEFAULT']>> {

spring controller中是有参数的,比如当前页码。
请帮忙看看是我什么地方没有配置正确吗?

@RequestBody pojo 不能接收到入参

场景描述:引入jimmer-apt后,@requestbody pojo 不能接收到入参。删除jimmer dependency后可以正常解析。
当前版本:0.6.15
依赖:jimmer-spring-boot-starter jimmer-apt。
尝试降级至0.6.10也存在这个问题。其它版本未尝试

多module项目启动失败

版本:0.6.18
详细描述:
在多module的spring boot项目中,尝试使用@EnableJimmerRepositories注解注入Jimmer Repositories,项目启动失败,提示找不到Jimmer Reposiories。
错误信息:
image
@EnableJimmerRepositories注解:
image

0.5.21版本中JRepository实现的deleteAll()不执行

RT.

查看源码JRepositoryImpl.deleteAll()实现调用的是

    @Override
    public void deleteAll() {
        Mutations
                .createUpdate(sqlClient, immutableType, (d, t) -> {})
                .execute();
    }

是否应该调用createDelete? 手误?还是我的理解错误?

[Feature Request] Map json column type

希望可以简化数据库 json 列的映射。
目前来说,将数据库表中 json 列映射至 entity,需要自定义 ScalarProvider 来进行列的序列化反序列化,但是每有一个这种列,都要定义一个ScalarProvider。希望可以有一个 Json 相关通用的处理。例如 (参考 hypersistence-utils):

// 加入 @Type注解,指定该列为 JsonType,即可自动(反)序列化,无需定义 ScalarProvider
@Column(columnDefinition = "jsonb")
@Type(JsonType.class)
private ApiAccessRequestParam requestParams

Repository可以提供通过Predicate进行查询的方法吗

版本: 0.7.0

JRepository或KJRepository中没有提供findAll(Predicate predicate)findOne(Predicate predicate)这样的方法
类似QueryDsl中的QuerydslPredicateExecutor:

public interface QuerydslPredicateExecutor<T> {
        Optional<T> findOne(Predicate predicate);

	Iterable<T> findAll(Predicate predicate);
}

是否可以考虑实现这样的方法呢?

我尝试实现这样的方法时, 碰到了一个问题

SqlClient没有createQuery(Class<?> entityClass)这样能够基于实体类型创建查询的方法, 只有通过Table<E>创建查询的方法, 因此必须通过repository提供Table对象才可能实现.
例如:

public interface BaseJimmerRepository<E, ID> extends JRepository<E, ID> {

  <T extends TableProxy<E>> T table();

  default List<E> findAll(Predicate predicate) {
    return sql().createQuery(table()).where(predicate).select(table()).execute();
  }
}

实体的Repository:

public interface DeviceJimmerRepository extends BaseJimmerRepository<Device,Long> {
   @Override default DeviceTable table() {
    return DeviceTable.$;
  }
}

Repository中能内置实现这种方法吗, 亦或者提供方便检索实体对应的Table的方法呢?

------------------------------------编辑

我找到了JRepositoryImpl中的一个方法org.babyfish.jimmer.spring.repository.support.JRepositoryImpl#createQuery

    private ConfigurableRootQuery<?, E> createQuery(Fetcher<E> fetcher, TypedProp.Scalar<?, ?>[] sortedProps) {
        MutableRootQueryImpl<Table<E>> query =
                new MutableRootQueryImpl<>(sqlClient, immutableType, ExecutionPurpose.QUERY, false);
        Table<E> table = query.getTable();
        for (TypedProp.Scalar<?, ?> sortedProp : sortedProps) {
            if (!sortedProp.unwrap().getDeclaringType().isAssignableFrom(immutableType)) {
                throw new IllegalArgumentException(
                        "The sorted field \"" +
                                sortedProp +
                                "\" does not belong to the type \"" +
                                immutableType +
                                "\" or its super types"
                );
            }
            PropExpression<?> expr = table.get(sortedProp.unwrap().getName());
            Order astOrder;
            if (sortedProp.isDesc()) {
                astOrder = expr.desc();
            } else {
                astOrder = expr.asc();
            }
            if (sortedProp.isNullsFirst()) {
                astOrder = astOrder.nullsFirst();
            }
            if (sortedProp.isNullsLast()) {
                astOrder = astOrder.nullsLast();
            }
            query.orderBy(astOrder);
        }
        query.freeze();
        return query.select(fetcher != null ? table.fetch(fetcher) : table);
    }

也许我知道该怎么自己实现了

----------------------------编辑

出问题了
jdk版本: 17
jimmer版本: 0.7.0
异常栈:

java.lang.IllegalArgumentException: Cannot resolve the root table xxx.xxx.xxx.Device
	at org.babyfish.jimmer.sql.ast.impl.AstContext.resolveRootTable(AstContext.java:85) ~[jimmer-sql-0.7.0.jar:na]
	at org.babyfish.jimmer.sql.ast.table.spi.AbstractTypedTable.__resolve(AbstractTypedTable.java:334) ~[jimmer-sql-0.7.0.jar:na]
	at org.babyfish.jimmer.sql.ast.impl.table.TableProxies.resolve(TableProxies.java:142) ~[jimmer-sql-0.7.0.jar:na]
	at org.babyfish.jimmer.sql.ast.impl.PropExpressionImpl.accept(PropExpressionImpl.java:109) ~[jimmer-sql-0.7.0.jar:na]
	at org.babyfish.jimmer.sql.ast.impl.ComparisonPredicate.accept(ComparisonPredicate.java:26) ~[jimmer-sql-0.7.0.jar:na]
	at org.babyfish.jimmer.sql.ast.impl.query.AbstractMutableQueryImpl.accept(AbstractMutableQueryImpl.java:191) ~[jimmer-sql-0.7.0.jar:na]
	at org.babyfish.jimmer.sql.ast.impl.query.AbstractConfigurableTypedQueryImpl.accept(AbstractConfigurableTypedQueryImpl.java:53) ~[jimmer-sql-0.7.0.jar:na]
	at org.babyfish.jimmer.sql.ast.impl.query.ConfigurableRootQueryImpl.accept(ConfigurableRootQueryImpl.java:21) ~[jimmer-sql-0.7.0.jar:na]
	at org.babyfish.jimmer.sql.ast.impl.query.ConfigurableRootQueryImpl.preExecute(ConfigurableRootQueryImpl.java:201) ~[jimmer-sql-0.7.0.jar:na]
	at org.babyfish.jimmer.sql.ast.impl.query.ConfigurableRootQueryImpl.executeImpl(ConfigurableRootQueryImpl.java:155) ~[jimmer-sql-0.7.0.jar:na]
	at org.babyfish.jimmer.spring.repository.SpringConnectionManager.execute(SpringConnectionManager.java:22) ~[jimmer-spring-boot-starter-0.7.0.jar:na]
	at org.babyfish.jimmer.sql.ast.impl.query.ConfigurableRootQueryImpl.execute(ConfigurableRootQueryImpl.java:135) ~[jimmer-sql-0.7.0.jar:na]
	at org.babyfish.jimmer.sql.ast.impl.query.ConfigurableRootQueryImpl.execute(ConfigurableRootQueryImpl.java:21) ~[jimmer-sql-0.7.0.jar:na]
	at xxx.xxx.xxx.xxx..xxx.BaseJimmerRepository.findAll(BaseJimmerRepository.java:69) ~[classes/:na]

其中BaseJimmerRepository中的代码如下:

@NoRepositoryBean
public interface BaseJimmerRepository<E>
    extends JRepository<E, Long> {

  private ConfigurableRootQuery<?, E> createQuery(
      Predicate predicate, Fetcher<E> fetcher, TypedProp.Scalar<?, ?>[] sortedProps) {
    var immutableType = type();
    MutableRootQueryImpl<Table<E>> query =
        new MutableRootQueryImpl<>(sql(), immutableType, ExecutionPurpose.QUERY, false);
    Table<E> table = query.getTable();
    for (TypedProp.Scalar<?, ?> sortedProp : sortedProps) {
      if (!sortedProp.unwrap().getDeclaringType().isAssignableFrom(immutableType)) {
        throw new IllegalArgumentException(
            "The sorted field \""
                + sortedProp
                + "\" does not belong to the type \""
                + immutableType
                + "\" or its super types");
      }
      PropExpression<?> expr = table.get(sortedProp.unwrap().getName());
      Order astOrder;
      if (sortedProp.isDesc()) {
        astOrder = expr.desc();
      } else {
        astOrder = expr.asc();
      }
      if (sortedProp.isNullsFirst()) {
        astOrder = astOrder.nullsFirst();
      }
      if (sortedProp.isNullsLast()) {
        astOrder = astOrder.nullsLast();
      }
      query.orderBy(astOrder);
    }
    var tableMutableRootQuery = query.where(predicate);
    query.freeze(); 
    return tableMutableRootQuery.select(fetcher != null ? table.fetch(fetcher) : table);
  }

  default List<E> findAll(Predicate predicate) {
    return createQuery(predicate).execute(); // 调用execute报错
  }

controller调用的代码

  @GetMapping("test")
  public List<xxx.xxx.xxx.xxx.Device> test() {
    return deviceJimmerRepository.findAll(DeviceTable.$.mac().eq("0011AABBCC00"));
  }

看起来是MutableRootQueryImplgetTable返回的Table不能用来组成条件.

所以还是回到最开始的问题: 是否考虑由Repository提供通过Predicate的查询, 或可以通过实体类检索Table对象的方法, 如果不考虑的话, 我就只能采用实体的Repository提供table的方式了.

WeakJoin的表,在select中传入对象,报错Cannot resolve the root table xxx

log表weakJoin user表,然后使用如下查询

        var list = sqlClient.createQuery(logTable)
                            .where(wkUser.username().eq("ombs"))
                            .where(logTable.operationStartTime().ge(startTime))
                            .where(logTable.operationEndTime().le(endTime))
                            .where(logTable.operationAction().eq("登录").or(logTable.operationAction().eq("退出")))
                            .orderBy(logTable.operationStartTime().desc())
                            .select(logTable, user.utype())
                            .limit(size, page * size)
                            .execute();

会报错Cannot resolve the root table com.capitek.dasop.entity.User

在select中不写对象,而直接写对应字段,不会出现此问题

较长的属性名导致生成的xxxDraft.kt文件出现自动换行从而导致编译错误

版本:0.6.1
语言:Kotlin
Kotlin编译器版本:1.7.10
Gradle依赖:

implementation("org.babyfish.jimmer:jimmer-spring-boot-starter:0.6.1")
ksp("org.babyfish.jimmer:jimmer-ksp:0.6.1")

ksp生成代码ReimbursementDraft.kt
issue
ksp报错为:
e: (路径省略)\entity\ReimbursementDraft.kt: (621, 25): Expecting an element
如图,大概是第621行的!==被错误地换行导致其出现在了行首,导致编译错误,我个人手动将!==前的换行删掉便不再编译报错(我个人并未测试运行时是否会出现异常)

ID and GeneratedValue

Jimmer Ver: 0.7.37
Dev JDK Ver: 17

对于ID,文档中提到,对Java而言,不能是8种基本类型的装箱类型。
然而UserIdGenerator使用了泛型,只能指定装箱类型Long,导致始终无法使用long类型的ID。


@entity
public interface Entity{
@id
@GeneratedValue(generatorType = SnowflakeIdGenerator.class)
long id();
}


public class SnowflakeIdGenerator implements UserIdGenerator {

@Override
public Long generate(Class<?> entityType) {
    return 1L;
}

}


Caused by: org.babyfish.jimmer.meta.ModelException: Illegal property "Entity.id", the generator type is "SnowflakeIdGenerator" generates id whose type is "java.lang.Long" but the property returns "long"

由于目前ScalarProvider对sqlType的限制,无法完成从对象到PostgreSQL中jsonb类型的映射

Jimmer版本 0.7.5

在数据库中有一列jsonb类型,想当然的用ScalarProvider写出如下转换:
ScalarProvider

但是在org.babyfish.jimmer.sql.runtime.ReaderManager#BASE_READER_MAP中,对ScalarProvider#sqlType的类型有如下限制:
BASE_READER_MAP

如果ScalarProvider#sqlType不在其中,则会抛出异常(org.babyfish.jimmer.sql.runtime.ReaderManager#scalarReader):
sqlType异常

...于是只能暂时把列类型改成text,写成这个样子:
图片

希望可以提供类型限制宽松一点的数据库无关的转换方式。

另外这种方式还有一个限制,若在此处完成ScanDimensionParam -> jsonb的转换,则所有实体中的所有ScanDimensionParam类型的字段都会被转换成jsonb,感觉...影响范围太大了

多模块项目启动时 `EntityManager.combine` 报错:`is not entity`

报错日志:

Caused by: java.lang.IllegalArgumentException: "io.github.AbstractEntity" is not entity
	at org.babyfish.jimmer.sql.runtime.EntityManager.<init>(EntityManager.java:35)
	at org.babyfish.jimmer.sql.runtime.EntityManager.combine(EntityManager.java:108)
	at io.elva.server.config.JimmerConfiguration.entityManager(JimmerConfiguration.kt:27)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:139)
	... 48 common frames omitted

项目为多模块,因此在配置jimmer时使用了EntityManager.combinecombine函数在最后进行类注册时,没有过滤掉非 @Entity注解的类

for (EntityManager entityManager : entityManagers) {
for (ImmutableType type : entityManager.getAllTypes(null)) {
classes.add(type.getJavaClass());
}
}
return new EntityManager(classes);

@Bean
fun entityManager(): EntityManager {
    return EntityManager.combine(
        io.github.core.domain.ENTITY_MANAGER,
        io.github.user.domain.ENTITY_MANAGER
    )
}

// entity 基本公共类
@MappedSuperclass
interface AbstractEntity {
    val createTime: LocalDateTime

    val updateTime: LocalDateTime

    val createBy: String?

    val updateBy: String?
}

// entity
@Table(name = "sys_api_access_log")
@Entity
interface ApiAccessLog : AbstractEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long
    val userId: Long?

    ... ...
}

[BUG] Native SQL表达式中,Sql占位符解析逻辑有误

版本:0.7.0
详细描述:在解析类似“concat(%e, '/', %e, '/', %e) = concat(%e, '/', %e, '/', %e)”这种有超过两个占位符的表达式时,在表达式确定无误的情况下抛出异常“Too Many Expressions”
出错原因
在org.babyfish.jimmer.sql.kt.ast.expression.impl.SqlDSL#addExpressionPlaceholder方法的第70行位置,直接对expressionPlaceholder实例变量的next属性赋值最新位置的%e,会导致head(第一个%e)的next永远是最后一个位置的%e,也因此在第三个%e时会抛出异常
addExpressionPlaceholder
可能的解决方案

  1. 在为head的next赋值之前,先找到当前已经处理的最新的%e,再.next = it
  2. 不使用head,新增一个current变量表示当前最新的%e,current.next = it

希望实现支持子查询的分页查询

在数据量比较大的情况下,单纯的分页查询效率不如先用子查询查出主键id 再用主键id关联显示数据的效率高,希望可以支持子查询的分页查询

是否可以支持将表关系定义持久化到数据库里?

提这个问题的时候我似乎意识到这与ksp可能有冲突,但我还是很好奇有没有这种可能性?

我希望将表关系的定义持久化是因为我希望能够在运行时动态配置他们,这样我就有可能实现通用数据访问层了。
进一步地,通过某种手段将查询操作符映射为字符串表达式,那么只要建个表就可以应对大多数的查询场景了。

database-validation-mode throws DatabaseValidationException

When using the database-validation-mode configuration, Jimmer threw an exception DatabaseValidationException, which indicated that there was no database table named shipments.
However, I do have this table in my database. After removing the database-validation-mode configuration, the project can run normally.
image

枚举类做查询条件时报错

jimmer 版本: 0.7.9

枚举类做查询条件使用in

Cannot convert the value "1" of prop "org.github.entity.Order.orderStatus" by scalar provider "org.babyfish.jimmer.sql.runtime.EnumProviderBuilder$EnumProvider"

代码如下:
下面的代码会报错

.where(orderInfo.orderStatus().in(Arrays.asList(OrderStatusEnum.DONE, OrderStatusEnum.NOOP)))

下面的代码不会报错

.where(orderInfo.orderStatus().eq(OrderStatusEnum.DONE))

.where(orderInfo.orderStatus().ne(OrderStatusEnum.DONE))

如果使用0.7.5 不会报错

[Feature Request]Add an API to get only one result from query

Even though I know explicitly that the query will return only one result, I need to use List to receive the result set and use list.get(0) to return one result, which seems redundant.

    public Role getRoleById(int id) {
        RoleTable roleTable = new RoleTable();
        List<Role> roles = sqlClient.createFluent()
                .query(roleTable)
                .where(roleTable.id().eq(id))
                .select(roleTable)
                .execute();
        LOGGER.info("getRole: {}", roles);
        return roles.get(0);
    }

I suggest it can be simplified in the following way:

    public Role getRoleById(int id) {
        RoleTable roleTable = new RoleTable();
        Optional<Role> role = sqlClient.createFluent()
                .query(roleTable)
                .where(roleTable.id().eq(id))
                .selectOne(roleTable)
                .execute();
        LOGGER.info("getRole: {}", role.get());
        return role.get();
    }

Add an API called selectOne to get the unique result and wrap it with Optinal.

能不能加入跨服务实体抓取数据?

比如,A实体在S1服务中,B实体在S2服务中,我在A服务中定义B类型属性时告诉它是远程数据对象,在抓取B数据时候就访问约定的远程访问接口

[建议]一些对本项目建议

您好,我是在b站看到你的jimmer视频的,我对这个项目设计理念非常感兴趣,我希望能参入到这个开源项目里面来,首先如果想要组好一个开源项目应该有良好的编码习惯,我觉得应该先把本土化市场做好,再考虑其他国内。我看到你已经有官网了,但是代码仓库代码提交还是感觉差一点意思,一个开源项目想做大就需要更多的开发者参入进来,你一个把这个仓库设置一个组织仓库,然后把这个项目写一些文章到一些技术社区去做推广,谢谢,这是我的建议。

[Feature Request] 业务主键联表

有些时候,没有办法在联表时获取到表中的逻辑主键,只能以业务主键进行联表操作,如下两种情况:

-- 两边都用多业务主键
select *
from data_security_table_result tr
         join database_table_meta_info tm
              on concat(tr.source, '/', tr.db_name, '/', tr.table_name)
                  =
                 concat(tm.source, '/', tm.db_name, '/', tm.table_name)
-- 一边用单业务主键,一边用多业务主键
select *
from outgoing_result "or"
         join database_table_meta_info tm
              on "or".obj_name
                  =
                 concat(tm.source, '/', tm.db_name, '/', tm.table_name)

希望可以对此提供支持

value 作为实体类的字段时,生成的代码报错

版本:0.6.26
详细描述:value 作为实体类的字段时,生成的 Draft 文件里的实现类中的两个 __set 方法存在语法错误,类字段与方法参数重名,需要加上 this。
另外 IllegalArgumentException 里的错误信息,漏了属性名称后面的单引号。

image

[BUG] @key注解和@OneToOne一起添加到一个属性上时,生成的列名不对

如题,在Key和OneToOne同时作用在一个注解上时,最终生成的SQL语句中的列名是把属性名称全大写下加划线,是一个不存在的列

实体接口定义
实体接口定义

会导致如下报错:
Cannot execute SQL statement: select tb_1_.ID, tb_1_.CATALOG_ID, tb_1_.GROUP from SCAN_DIMENSION_CATALOG_GROUP as tb_1_ where tb_1_.CATALOG_ID = ? and tb_1_.GROUP = ?, variables: [14, 9]

在属性上新增JoinColumn也不起作用:
属性上新增JoinColumn
依然是同样的列名,同样的报错
JoinColumn报错

Support of customized Jackson annotation for serialization and deserialization

As I inject the ImmultiableModule into jackson ObjectMapper

@Bean
@Primary
public ObjectMapper objectMapper() {
    return new ObjectMapper()
            .registerModule(new ImmutableModule());
}

I find that customized Jackson annotation lapse and cant get the right result.

@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@JacksonAnnotationsInside
@JsonSerialize(using = EnumSerializer.class)
public @interface EnumSerialize {

}

Is there any way to fix, or plan to support?

[功能]验证功能添加load状态前置

当前的验证,如果属性是unload状态的话,是不会经过校验的,但写校验的目的就是确保该属性符合业务要求,例如

@Entity
@Table(name = "d_role")
public interface Role {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    int id();

    @Nullable
    String code();

    @NotNull
    String name();
}

该实体要求id与name不可为空,然后用于在dao层查询。
现在如果接收参数时,name没有传值,例如:

{
    "id": 1
}

此时name是unload状态,则不过经过notnull校验,不会报错'name' cannot be null
dao层还要在验证一次isload,不仅代码臃肿,而且也不符合直觉。
是否应该由框架在校验notnull之前先完成isload判断?

怎么映射json等复杂类型字段呢?

目前使用postgresql,表中有一个Json字段,如何映射到@Entity类中呢?

文档里没看到相关内容,直接用类接收就出现类型转换错误。
Failed the convert the result value at column $6, the expected type is 'xxxx', but the actual type is 'org.postgresql.util.PGobject'

[Feature Request]Please simplify the judgment of param's load status

When I want to determine whether an attribute is loaded or not, the current API has only two ways

boolean pageLoaded = ImmutableObjects.isLoaded(role, "page");
boolean pageLoaded = ImmutableObjects.isLoaded(role, 12);

Both of these are not very user-friendly, and both hard-coded strings and numbers are error-prone。
I think it can be simplified to

boolean pageLoaded = ImmutableObjects.isLoaded(role, role.page());

Even more simpliy like this

boolean pageLoaded = ImmutableObjects.isLoaded(role.page());

enum如何自定义显示的内容呢?

enum如何自定义显示的内容呢?

我在代码中只看到了EnumProvider相关的内容,目前应该是只能将数据库中的字段转换为 enum.name();

是否有其他的转换方法呢?

[BUG]级联保存数据时,当前对象与关联对象都没有设置ID或KEY,会导致更新失败

常规逻辑,集联保存时,当前对象与关联对象的ID一般情况下是不会有值的,默认是数据库生成,所以我在角色实体Role和权限实体permission上都设置了ID生成策略为GenerationTpye.IDENTITY。
mmexport1663841001232.png

但是保存的对象中没有传双方的ID,
mmexport1663841004608.png
即使我设置了setAutoAttachingAll(),指定了SaveMode.INSERT_ONLY
mmexport1663840978470.png
jimmer依旧还要判断ID或KEY,导致报错
mmexport1663840986068.png

我认为在集联保存且指定为insert_only时,不应该进行此ID或KEY判断,否则在保存前需要手动生成一个ID或KEY给当前对象及其关联对象,相当麻烦且不符合常规逻辑。

使用@IdView,fetcher中不查主表就会在系统启动后,终止服务

Jimmer版本:0.7.22

伪代码如下:

public interface Dict {
	String name();
}

public interface DictItem {
	@ManyToOne
    @Nullable
    @JoinColumn(name = "dict_id")
	Dict dict();

	@IdView
    @Nullable
	Long dictId();
}

// 如果controller中有以下Fetcher,启动后会报错
DictItemFetcher.$.dictId()

// 如下写法则不会
DictItemFetcher.$.dict().dictId()
Application run failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'typeScriptController' defined in class path resource [org/babyfish/jimmer/spring/cfg/JimmerAutoConfiguration.class]: Unsatisfied dependency expressed through method 'typeScriptController' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'metadataFactoryBean': FactoryBean threw exception on object creation; nested exception is java.lang.NullPointerException

下图单元测试,DictItemFetcher.$.dictId()则不会报错
image

between SQL语句拼接错误

在BetweenPredicate中的renderTo方法里面,builder.sql(if (negative) " not between " else "between"),由于between前后没有空格导致SQL语句拼接错误

[Feature Request] Add an API to get the count directly

Pagination Query are too cumbersome now.

TypedRootQuery<Long> countQuery = query
    .reselect((q, t) ->
        q.select(t.count())
    )
    .withoutSortingAndPaging();

int rowCount = countQuery.execute().get(0).intValue();
List<Book> books = query
    .limit(rowCount / 3, rowCount / 3)
    .execute();

I wish it could be simplified to an API to get the count directly, like this

long count = query.getCount();

Because I think the specific implementation details should be understood as source code and should not appear in everyday use. It is much easier and faster to use only one API to get the results.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.