如何从 for 循环中获取 SOQL 查询
How to get a SOQL query out of a for loop
已添加代码。
我在这里无休止地寻找解决方案,但找不到解决方案,请帮忙!
我有三个对象(A、B 和 C)。 A 有对 B 的查找,B 是 C 的主人(详细信息)。 A 和 C 都有很多记录与每个 B 记录相关。
我想要一份工作 运行 从对象 C 获取记录的子集(通常大约有 5,000 条记录)。然后遍历每一个并获取对象 A 上查找相同对象 B 记录的记录,总结一个对象 A 数字字段,并将其放在 C 记录上。
我已经成功地让它在小范围内工作,<100 个对象 C 记录。但是每个 Object C 记录都需要一个新的 SOQL 查询,因为我在获取所有 Object C 记录后在 for 循环中迭代它们。另外,我知道在循环中进行查询并不是最佳做法。
我怎样才能让它工作?由于记录与对象 B 共享关系,是否有另一种方法可以从匹配的对象 A 记录中获取数据?或者有什么方法可以提取两个列表,一个对象 C 和一个对象 A。然后汇总对象 A 记录并将列表排列成某种方式?
提前致谢!
代码:
public class nightlyJob {
public static void updateNumbers(){
integer I = 29;
List<ObjectC__c> CUpdateList = new List<ObjectC__c>();
List<ObjectC__c> CpullList =
[SELECT ID, Index__c, ObjectB__r.id
FROM ObjectC__c
WHERE Index__c = :I];
for(ObjectC__c s : CpullList){
List<ObjectA__c> AList =
[SELECT ObjectB__c, Number__c
FROM ObjectA__c
WHERE ObjectB__c = :s.ObjectB__r.Id];
decimal NumSum = 0;
for(ObjectA__c a : AList){
NumSum = a.Number__c + NumSum;
}
s.Num__c = NumSum;
CUpdateList.add(s);
}
update CUpdateList;
}
}
看来您目前确实缺少几个基本概念。
您在 SFDC 开发中遇到的最大问题是 "database" 操作非常昂贵并且受到严格限制。这不仅仅是 "best practice" 的问题:如果在单个事务中超过这些限制——SOQL 调用次数、返回记录数、更新记录数、DML 语句数等——你的事务将失败。有关详细信息,请在线搜索 "Salesforce Execution Governors and Limits"。
您可以编写在这些限制范围内工作的代码,但有一点学习曲线。
首先,学习将集合与 SOQL 查询结合使用,以使您的 SOQL 查询脱离循环。这是a.k.a。 "bulkfication" 它是 SFDC 开发的基础:
List<ObjectC__c> CpullList =
[SELECT ID, Index__c, ObjectB__r.id
FROM ObjectC__c
WHERE Index__c = :I];
// Create a map with the results of this query.
// key=ObjectC__c.Id, value = Object__c record
Map<Id, ObjectC__c> objCmap = Map<Id, ObjectC__c>(CpullList);
// Build a set of all the Object_B id's from this result set
Set<Id> objBids = new Set<Id>();
for (ObjectC__c record : CpullList) {
objBids.add(record.ObjectB__r.id);
}
// Now you can use only one SOQL query instead of a loop
List<ObjectA> AList = [SELECT ObjectB__c, Number__c
FROM ObjectA__c
WHERE ObjectB__c in:objBids];
接下来,尽可能使用 "SOQL aggregate functions"。示例:在此处的代码中,您可以使用 "SUM()" 和 "group by" 而不是使用循环执行这些计算:
// Get the sum of ObjectA__c.Number__c for each Object B in objBIds
AggregateResult[] groupedResults = [select ObjectB__c,
sum(Number__c) sumA
from ObjectA__c
where ObjectB__c in: objBids
group by ObjectB__c];
for (AggregateResult ar : groupedResults) {
System.debug('Object B Id' + ar.get('Objectb__c'));
System.debug('Sum of ObjectA__c.Number__c' + ar.get('sumA'));
// Here, you might want to build a Map<Id, Integer> sumAmap:
// key=Object B ID, value=sumA
// and then use it along with objCmap to build a collection of Object C's
// for your update statement...
}
您可以继续这个过程并应用这些想法来提高代码的效率。
但即使您的方法尽可能高效地工作,您仍然可能 运行 由于要处理的记录数量而受到限制。到那时,您将需要了解 Batchable 接口、Queuable 接口和@future 调用(如何处理大量记录,跨事务拆分)这些信息实在太多,无法在单个 SO 答案中涵盖。
已添加代码。
我在这里无休止地寻找解决方案,但找不到解决方案,请帮忙!
我有三个对象(A、B 和 C)。 A 有对 B 的查找,B 是 C 的主人(详细信息)。 A 和 C 都有很多记录与每个 B 记录相关。
我想要一份工作 运行 从对象 C 获取记录的子集(通常大约有 5,000 条记录)。然后遍历每一个并获取对象 A 上查找相同对象 B 记录的记录,总结一个对象 A 数字字段,并将其放在 C 记录上。
我已经成功地让它在小范围内工作,<100 个对象 C 记录。但是每个 Object C 记录都需要一个新的 SOQL 查询,因为我在获取所有 Object C 记录后在 for 循环中迭代它们。另外,我知道在循环中进行查询并不是最佳做法。
我怎样才能让它工作?由于记录与对象 B 共享关系,是否有另一种方法可以从匹配的对象 A 记录中获取数据?或者有什么方法可以提取两个列表,一个对象 C 和一个对象 A。然后汇总对象 A 记录并将列表排列成某种方式?
提前致谢!
代码:
public class nightlyJob {
public static void updateNumbers(){
integer I = 29;
List<ObjectC__c> CUpdateList = new List<ObjectC__c>();
List<ObjectC__c> CpullList =
[SELECT ID, Index__c, ObjectB__r.id
FROM ObjectC__c
WHERE Index__c = :I];
for(ObjectC__c s : CpullList){
List<ObjectA__c> AList =
[SELECT ObjectB__c, Number__c
FROM ObjectA__c
WHERE ObjectB__c = :s.ObjectB__r.Id];
decimal NumSum = 0;
for(ObjectA__c a : AList){
NumSum = a.Number__c + NumSum;
}
s.Num__c = NumSum;
CUpdateList.add(s);
}
update CUpdateList;
}
}
看来您目前确实缺少几个基本概念。
您在 SFDC 开发中遇到的最大问题是 "database" 操作非常昂贵并且受到严格限制。这不仅仅是 "best practice" 的问题:如果在单个事务中超过这些限制——SOQL 调用次数、返回记录数、更新记录数、DML 语句数等——你的事务将失败。有关详细信息,请在线搜索 "Salesforce Execution Governors and Limits"。
您可以编写在这些限制范围内工作的代码,但有一点学习曲线。
首先,学习将集合与 SOQL 查询结合使用,以使您的 SOQL 查询脱离循环。这是a.k.a。 "bulkfication" 它是 SFDC 开发的基础:
List<ObjectC__c> CpullList =
[SELECT ID, Index__c, ObjectB__r.id
FROM ObjectC__c
WHERE Index__c = :I];
// Create a map with the results of this query.
// key=ObjectC__c.Id, value = Object__c record
Map<Id, ObjectC__c> objCmap = Map<Id, ObjectC__c>(CpullList);
// Build a set of all the Object_B id's from this result set
Set<Id> objBids = new Set<Id>();
for (ObjectC__c record : CpullList) {
objBids.add(record.ObjectB__r.id);
}
// Now you can use only one SOQL query instead of a loop
List<ObjectA> AList = [SELECT ObjectB__c, Number__c
FROM ObjectA__c
WHERE ObjectB__c in:objBids];
接下来,尽可能使用 "SOQL aggregate functions"。示例:在此处的代码中,您可以使用 "SUM()" 和 "group by" 而不是使用循环执行这些计算:
// Get the sum of ObjectA__c.Number__c for each Object B in objBIds
AggregateResult[] groupedResults = [select ObjectB__c,
sum(Number__c) sumA
from ObjectA__c
where ObjectB__c in: objBids
group by ObjectB__c];
for (AggregateResult ar : groupedResults) {
System.debug('Object B Id' + ar.get('Objectb__c'));
System.debug('Sum of ObjectA__c.Number__c' + ar.get('sumA'));
// Here, you might want to build a Map<Id, Integer> sumAmap:
// key=Object B ID, value=sumA
// and then use it along with objCmap to build a collection of Object C's
// for your update statement...
}
您可以继续这个过程并应用这些想法来提高代码的效率。
但即使您的方法尽可能高效地工作,您仍然可能 运行 由于要处理的记录数量而受到限制。到那时,您将需要了解 Batchable 接口、Queuable 接口和@future 调用(如何处理大量记录,跨事务拆分)这些信息实在太多,无法在单个 SO 答案中涵盖。