如何将 soql 计数的聚合结果存储在列表中
How can I store the aggregated result of a soql count in a List
我正在计算一个联系人拥有的相关帐户的数量。
此数字应存储在 "Contact" 上的自定义字段中,并应在每次添加或删除关系时更新,因此通过触发代码。
为了计算当前关系的数量,我想将以下查询的结果存储在我想在之后循环以更新联系人记录的列表中:
List<AccountContactRelation> acr = new List<AccountContactRelation>([SELECT ContactId, Count(Id) FROM AccountContactRelation WHERE ContactId IN :contactIds AND Active__c = true GROUP by ContactId]);
但是,这会引发错误:
"System.ListException: Row with null Id at index: 0"
如何构建此列表以供进一步处理?
亲切的问候,
斯特凡
问得好。
一般来说,Apex 中的 运行 SOQL 生成一个值,该值具体化为单个 SObject
class 或 List<SObject>
(通用 SObject,或确切的 SObject 类型以匹配 FROM
子句类型)。这正是您想要做的。
然而,当 运行 在 Apex 中聚合 SOQL 时,有一些不同 rules。
首先,如果聚合结果为单个简单数值,您可能会得到 return 类型的 Integer
。
Integer myAggregate = [SELECT Count() FROM Account WHERE Type = 'Prospect'];
System.debug(myAggregate); //output: 36
然而,对于您正在做的事情,有一种特殊的聚合值泛型类型,称为 AggregateResult
。 AggregateResult
实例本质上就像一个映射,其中每个字段都通过其键访问,并使用 get('fieldName')
访问器检索。您的查询将在 List
中 return。这是一个可能的流程,您可以如何使用它来创建要更新的联系人列表。
List<Contact> contactsToUpdate = new List<Contact>();
List<AggregateResult> resultList = [SELECT ContactId, Count(Id) relationCount
FROM AccountContactRelation
WHERE ContactId IN :contactIds
AND Active__c = true GROUP by ContactId];
for (AggregateResult ar: resultList) {
//assign to contacts here.
Contact contactToUpdate = new Contact();
contactToUpdate.Id = (Id) ar.get('ContactId');
contactToUpdate.Custom_Count_Field__c = (Integer) ar.get('relationCount');
contactsToUpdate.add(contactToUpdate);
}
// always perform DML outside of loops in Apex
update contactsToUpdate; //you may want to use Database.update()
有几点需要注意。
- 执行内联 SOQL 时不需要调用
SObject
或 List
构造函数。它是隐式的。
- 在聚合查询中,注意别名的使用。虽然别名在 SOQL 中几乎无关紧要(在我看来),但在这里它们是必不可少的,否则会为所有称为
expr0
、expr1
等的聚合值分配一个通用键。不要这样做对你自己来说。
AggregateResult
字段的通用类型都是Object
。您需要转换它们以匹配基础 SObject 字段类型。就我而言,我假设您的自定义字段定义为数字字段。
我正在计算一个联系人拥有的相关帐户的数量。 此数字应存储在 "Contact" 上的自定义字段中,并应在每次添加或删除关系时更新,因此通过触发代码。 为了计算当前关系的数量,我想将以下查询的结果存储在我想在之后循环以更新联系人记录的列表中:
List<AccountContactRelation> acr = new List<AccountContactRelation>([SELECT ContactId, Count(Id) FROM AccountContactRelation WHERE ContactId IN :contactIds AND Active__c = true GROUP by ContactId]);
但是,这会引发错误:
"System.ListException: Row with null Id at index: 0"
如何构建此列表以供进一步处理?
亲切的问候, 斯特凡
问得好。
一般来说,Apex 中的 运行 SOQL 生成一个值,该值具体化为单个 SObject
class 或 List<SObject>
(通用 SObject,或确切的 SObject 类型以匹配 FROM
子句类型)。这正是您想要做的。
然而,当 运行 在 Apex 中聚合 SOQL 时,有一些不同 rules。
首先,如果聚合结果为单个简单数值,您可能会得到 return 类型的 Integer
。
Integer myAggregate = [SELECT Count() FROM Account WHERE Type = 'Prospect'];
System.debug(myAggregate); //output: 36
然而,对于您正在做的事情,有一种特殊的聚合值泛型类型,称为 AggregateResult
。 AggregateResult
实例本质上就像一个映射,其中每个字段都通过其键访问,并使用 get('fieldName')
访问器检索。您的查询将在 List
中 return。这是一个可能的流程,您可以如何使用它来创建要更新的联系人列表。
List<Contact> contactsToUpdate = new List<Contact>();
List<AggregateResult> resultList = [SELECT ContactId, Count(Id) relationCount
FROM AccountContactRelation
WHERE ContactId IN :contactIds
AND Active__c = true GROUP by ContactId];
for (AggregateResult ar: resultList) {
//assign to contacts here.
Contact contactToUpdate = new Contact();
contactToUpdate.Id = (Id) ar.get('ContactId');
contactToUpdate.Custom_Count_Field__c = (Integer) ar.get('relationCount');
contactsToUpdate.add(contactToUpdate);
}
// always perform DML outside of loops in Apex
update contactsToUpdate; //you may want to use Database.update()
有几点需要注意。
- 执行内联 SOQL 时不需要调用
SObject
或List
构造函数。它是隐式的。 - 在聚合查询中,注意别名的使用。虽然别名在 SOQL 中几乎无关紧要(在我看来),但在这里它们是必不可少的,否则会为所有称为
expr0
、expr1
等的聚合值分配一个通用键。不要这样做对你自己来说。 AggregateResult
字段的通用类型都是Object
。您需要转换它们以匹配基础 SObject 字段类型。就我而言,我假设您的自定义字段定义为数字字段。