Prisma Kysely查询中父级字段被嵌套关联覆盖问题
字段覆盖问题排查与解决
问题原因
执行innerJoin('BrandSupplier')后调用selectAll(),会同时查询Product和BrandSupplier两个表的所有字段。由于两个表存在id、name这类同名字段,数据库返回的结果集中,后出现的BrandSupplier字段会覆盖先出现的Product字段,最终导致返回对象里的id、name被替换成了品牌供应商的数据。后续通过jsonObjectFrom嵌套查询brandSupplier的操作,只是额外添加了嵌套对象,无法修正已发生的字段覆盖。
解决方法
核心思路是只查询需要的字段,避免同名字段冲突,以下是两种可行实现方式:
方式一:明确指定查询Product的所有字段
将selectAll()替换为明确选择Product表的所有字段,排除BrandSupplier的字段,从根源避免冲突:
await prisma.$kysely .selectFrom('Product') // 仅选择Product表的所有字段,而非关联后的所有表字段 .select('Product.*') .innerJoin('BrandSupplier', 'Product.brandSupplierId', 'BrandSupplier.id') .where(({ or }) => or([ sql<SqlBool>`word_similarity("Product".name, 'heinnekinn') > 0.3`, sql<SqlBool>`word_similarity("BrandSupplier".name, 'heinnekinn') > 0.3` ]) ) .select((eb) => [ jsonObjectFrom( eb .selectFrom('BrandSupplier') .selectAll() .whereRef('BrandSupplier.id', '=', 'Product.brandSupplierId') ).as('brandSupplier') ]) .execute();
方式二:移除不必要的innerJoin,改用子查询过滤
如果innerJoin仅用于在where条件中匹配BrandSupplier.name,可以改用exists子查询实现过滤,避免不必要的表关联:
await prisma.$kysely .selectFrom('Product') .selectAll() .where(({ or, exists }) => or([ sql<SqlBool>`word_similarity("Product".name, 'heinnekinn') > 0.3`, // 用exists子查询替代innerJoin,实现品牌供应商名称的匹配逻辑 exists( eb.selectFrom('BrandSupplier') .whereRef('BrandSupplier.id', '=', 'Product.brandSupplierId') .where(sql<SqlBool>`word_similarity("BrandSupplier".name, 'heinnekinn') > 0.3`) ) ]) ) .select((eb) => [ jsonObjectFrom( eb .selectFrom('BrandSupplier') .selectAll() .whereRef('BrandSupplier.id', '=', 'Product.brandSupplierId') ).as('brandSupplier') ]) .execute();
两种方式均可解决字段覆盖问题:方式一更适合需要用到BrandSupplier其他字段的场景,方式二则更简洁,减少了不必要的表关联开销。
内容的提问来源于stack exchange,提问作者red house 87
相关产品推荐
相关产品推荐

