如何在TypeScript中向DataLoader传递自定义对象参数?
对象作为DataLoader Key的问题解决
问题现象
尝试将包含postId和userId的对象作为DataLoader的key传入,自定义缓存键函数后仍触发报错:
driverError: error: invalid input syntax for type integer: "{\"postId\":317,\"userId\":2}"
错误原因
- 数据库查询参数错误:在批量加载函数
batchLoadFn中,直接将对象数组keys传入In(),数据库驱动会自动把对象序列化为JSON字符串,而数据库期望接收整数类型的ID数组,导致类型不匹配报错。 - 缓存键函数未正确实现:默认的
cacheKeyFn将对象作为缓存键,但JavaScript中对象是引用类型,即使内容完全相同的两个对象也会被视为不同的键,无法实现缓存复用;你尝试的自定义函数返回对象或自定义类实例,同样无法解决引用类型的缓存键识别问题。
正确解决方案
1. 修复批量查询逻辑
从keys数组中提取出postId和userId的纯值数组,再传入In()条件。
2. 实现正确的缓存键函数
返回一个唯一的字符串作为缓存键(比如userId|postId的拼接格式),确保内容相同的对象会生成完全一致的缓存键。
完整代码示例
// 自定义缓存键函数:返回字符串格式的唯一标识 function cacheKeyFn({ postId, userId }: { postId: number; userId: number }) { return `${userId}|${postId}`; } export const createUpvoteLoader = () => new DataLoader<{ postId: number; userId: number }, Upvote | null, string>( async (keys) => { // 从keys数组中提取所有postId和userId的纯值数组 const postIds = keys.map(key => key.postId); const userIds = keys.map(key => key.userId); // 查询符合条件的所有点赞记录 const upvotes = await Upvote.findBy({ postId: In(postIds), userId: In(userIds) }); // 构建映射表,方便按key快速查找结果 const upvoteMap: Record<string, Upvote> = {}; upvotes.forEach(upvote => { upvoteMap[`${upvote.userId}|${upvote.postId}`] = upvote; }); // 按传入keys的顺序返回对应结果,无匹配则返回null return keys.map(key => upvoteMap[`${key.userId}|${key.postId}`] ?? null); }, { cacheKeyFn } );
额外说明
cacheKeyFn的返回值必须是可被Map正确识别为相同键的类型,字符串、数字等基本类型都适用,避免使用对象或自定义类实例。- 批量查询时必须明确提取ID纯值数组,不能直接将对象数组传入数据库查询条件,否则会触发类型转换错误。
内容的提问来源于stack exchange,提问作者jpr
相关产品推荐
相关产品推荐

