DynamoDb .NET对象持久化模型:LoadAsync中ScanCondition不生效求助
DynamoDB查询问题解析:ScanCondition不生效与QueryAsync异常
问题背景
我是DynamoDb领域的新手,恳请各位提供帮助。我有一张名为Tenant的DynamoDb表,其中TenantId是哈希主键,无其他键,还有一个布尔类型字段IsDeleted。我想要查询指定TenantId且未删除(IsDeleted == 0)的记录,遇到了以下问题:
- 有效代码(返回0条正确数据):
var filter = new QueryFilter("TenantId", QueryOperator.Equal, "2235ed82-41ec-42b2-bd1c-d94fba2cf9cc"); filter.AddCondition("IsDeleted", QueryOperator.Equal, 0); var dbTenant = await _genericRepository.FromQueryAsync(new QueryOperationConfig { Filter = filter }).GetRemainingAsync();
- 无效代码(返回1条已删除记录):
var queryFilter = new List<ScanCondition>(); var scanCondition = new ScanCondition("IsDeleted", ScanOperator.Equal, new object[]{0}); queryFilter.Add(scanCondition); var dbTenant2 = await _genericRepository.LoadAsync("2235ed82-41ec-42b2-bd1c-d94fba2cf9cc", new DynamoDBOperationConfig { QueryFilter = queryFilter, ConditionalOperator = ConditionalOperatorValues.And });
同时尝试QueryAsync方法时还抛出了异常:
var dbTenant2 = await _genericRepository.QueryAsync("2235ed82-41ec-42b2-bd1c-d94fba2cf9cc", new DynamoDBOperationConfig() { QueryFilter = new List<ScanCondition>() { new ScanCondition("IsDeleted", ScanOperator.Equal, 0) } });
问题原因与解决方案
1. 为啥LoadAsync里的ScanCondition完全没起作用?
其实很好理解——LoadAsync这个方法的定位就是通过主键精准捞单条记录,它底层调用的是DynamoDB的GetItem API,这个API只会根据哈希主键(如果有排序键就加上)找对应的那条数据,根本不会理会你传入的QueryFilter或者扫描条件。
你传的那些ScanCondition在这里直接被忽略了,所以它只返回了匹配TenantId的那条记录,管它IsDeleted是0还是1,这就是你拿到已删除条目的原因。
2. 那第一个Query方法为啥能正常工作?
你第一个代码用的FromQueryAsync是执行Query操作:
- 第一步先通过
TenantId(哈希主键)锁定对应的分区,把这个分区里所有匹配主键的记录捞出来(因为你没设排序键,所以最多一条) - 第二步再给这些记录加个
IsDeleted == 0的过滤条件,最后返回符合要求的结果。
这完全符合DynamoDBQuery操作的逻辑,所以结果是对的。
3. QueryAsync抛异常是咋回事?
你用QueryAsync时出错,大概率是因为条件类型用错了!QueryAsync对应的是Query操作,得用QueryFilter,而ScanCondition是给Scan操作准备的,把ScanCondition塞到QueryOperationConfig的QueryFilter里,肯定会因为类型不匹配或者参数错误抛出异常。
给你个正确的QueryAsync写法参考:
var queryConfig = new QueryOperationConfig { KeyConditionExpression = new Expression { ExpressionStatement = "TenantId = :tid", ExpressionAttributeValues = new Dictionary<string, DynamoDBEntry> { { ":tid", "2235ed82-41ec-42b2-bd1c-d94fba2cf9cc" } } }, FilterExpression = new Expression { ExpressionStatement = "IsDeleted = :isDel", ExpressionAttributeValues = new Dictionary<string, DynamoDBEntry> { { ":isDel", 0 } } } }; var dbTenant = await _genericRepository.QueryAsync(queryConfig).GetRemainingAsync();
或者用你熟悉的QueryFilter方式:
var filter = new QueryFilter("TenantId", QueryOperator.Equal, "2235ed82-41ec-42b2-bd1c-d94fba2cf9cc"); filter.AddCondition("IsDeleted", QueryOperator.Equal, 0); var dbTenant = await _genericRepository.QueryAsync(filter).GetRemainingAsync();
最后给你提个小建议
- 要通过主键查询再加过滤条件的话,别用
LoadAsync,它只做精准主键匹配; - 优先用
Query操作(不管是FromQueryAsync还是QueryAsync),比Scan高效太多,大表下差距特别明显; - 一定要分清
QueryFilter(给Query用)和ScanCondition(给Scan用),别搞混了哦。
内容的提问来源于stack exchange,提问作者Reza
相关产品推荐
相关产品推荐

