[R2DBC-Spring-Data-kofu]:在条件API中表达不同

[R2DBC-Spring-Data-kofu]:Expressing distinct in criteria API

您好,我尝试将 jpql 查询转换为条件 api。 sql 查询是 SELECT COUNT(DISTINCT id) FROM `user` WHERE login != :anonymousUser 我刚刚成功地达到了这个查询条件 SELECT COUNT(id) FROM `user` WHERE login != :anonymousUser 这是代码:

class UserRepository(
    private val repo: R2dbcEntityOperations
) {
    companion object {
        @JvmStatic
        private val userModel by lazy { User::class.java }
    }

    // expected query:
    //"SELECT COUNT(DISTINCT id) FROM `user` WHERE login != :anonymousUser"
    fun countAllByLoginNot(anonymousUser: String): Mono<Long> {
        return repo.select(userModel)
            //current query:
            //"SELECT COUNT(id) FROM `user` WHERE login != :anonymousUser"
            .matching(
                query(
                    where("login")
                        .not(anonymousUser).ignoreCase(true)
                )
            )
        .count()
    }
}

如何使用标准 API 引入不同?

我也遇到过类似的问题。 虽然我使用的是 java,但我似乎找到了一些相关的东西,希望对您有所帮助:

// template : R2dbcEntityTemplate
final StatementMapper statementMapper = template.getDataAccessStrategy().getStatementMapper();
statementMapper.createSelect("table_name")
    .distinct() // distinct!
    .doWithTable((table, spec) -> {
        // Do with table. 
        // See org.springframework.data.r2dbc.core.R2dbcEntityTemplate#doSelect or other.
        return  // return something
});

如果要对count函数进行去重,可能需要参考org.springframework.data.relational.core.sql.SimpleFunction实现一个新的class,比如CountDistinctFunction。你可以参考这个:


/**
 *
 * Function: {@code COUNT(DISTINCT ... )}
 *
 * @see org.springframework.data.relational.core.sql.Functions
 * @see org.springframework.data.relational.core.sql.SimpleFunction
 * @author ForteScarlet
 */
public class CountDistinctFunction implements Expression {
    private static final String FUNCTION_NAME = "COUNT";
    private final List<Expression> expressions;

    private CountDistinctFunction(List<Expression> expressions) {
        this.expressions = expressions;
    }

    /** getInstance. */
    public static CountDistinctFunction getInstance(Expression... expressions) {
        return new CountDistinctFunction(Arrays.asList(expressions));
    }

    /**
     * @see SimpleFunction#toString()
     */
    @Override
    public @NotNull String toString() {
        return FUNCTION_NAME + "(DISTINCT " + StringUtils.collectionToDelimitedString(expressions, ", ") + ")";
    }

    /**
     * @see SimpleFunction#getFunctionName()
     */
    public String getFunctionName() {
        return FUNCTION_NAME;
    }

    /**
     * @see SimpleFunction#getExpressions()
     */
    public List<Expression> getExpressions() {
        return Collections.unmodifiableList(expressions);
    }


    /**
     * @see org.springframework.data.relational.core.sql.AbstractSegment
     */
    @SuppressWarnings("JavadocReference")
    @Override
    public void visit(@NotNull Visitor visitor) {
        Assert.notNull(visitor, "Visitor must not be null!");

        visitor.enter(this);
        visitor.leave(this);
    }

    /**
     * @see org.springframework.data.relational.core.sql.AbstractSegment
     */
    @SuppressWarnings("JavadocReference")
    @Override
    public int hashCode() {
        return toString().hashCode();
    }

    /**
     * @see org.springframework.data.relational.core.sql.AbstractSegment
     */
    @SuppressWarnings("JavadocReference")
    @Override
    public boolean equals(Object obj) {
        return obj instanceof Segment && toString().equals(obj.toString());
    }
}

并使用它:

        R2dbcEntityTemplate template; = // template instance

        final StatementMapper statementMapper = template.getDataAccessStrategy().getStatementMapper();
        final StatementMapper.SelectSpec selectSpec = statementMapper.createSelect("your_table_name")
                .withCriteria(criteria)
                .doWithTable((table, spec) -> spec.withProjection(CountDistinctFunction.getInstance(table.column("id"))));

        final PreparedOperation<?> operation = statementMapper.getMappedObject(selectSpec);
        final Mono<Long> count = template.getDatabaseClient().sql(operation).map(r -> r.get(0, Long.class)).first();


虽然这个 post 已经很久了,但我还是会发表我的意见。如果有谁看到了,有更好的方案,也请告诉我,万分感谢!

(由 DeepL 翻译)