У меня есть три настраиваемых объекта: Книга, Кредит и Читатель. Loan — это связующий объект с отношениями поиска как с Book, так и с Reader. На диаграмме ниже показано их соотношение:

enter image description here

Я хочу создать триггер для объекта «Ссуда», который должен разрешать только создание записи о ссуде, только значение поля темы из объекта «Книга» аналогично значению поля темы из объекта «Читатель». Показать сообщение об ошибке, если значения обоих полей не равны.

Это мой код:

trigger LoanTrigger on Loan__c (before insert) {
    
    for (Loan__c myLoan : [SELECT Name,Book__r.Name, Book__r.Subject__c,
                           Reader__r.Name, Reader__r.Subject__c FROM Loan__c]) 
    {
        if(myLoan.Book__r.Subject__c != myLoan.Reader__r.Subject__c) 
        {
            myLoan.addError('BOOK AND READER SUBJECTS MUST BE SAME');
        } 
    }
}

Я получаю следующую ошибку при попытке сохранить кредитную запись:

LoanTrigger: выполнение BeforeInsert вызвано: System.FinalException: строка SObject не допускает ошибок Trigger.LoanTrigger: строка 8, столбец 1

1
Derek F 11 Июл 2021 в 01:42
Вы запрашиваете все кредиты, а не только те, которые вставляются. Почему?
 – 
Phil W
11 Июл 2021 в 01:52
Также обратите внимание, что во время перед вставкой нет идентификаторов для записей Trigger.new, поэтому вам нужно использовать совершенно другой способ запроса данных из связанных объектов, чем запрос, который у вас есть здесь. Соберите уникальные идентификаторы книг и записей читателей, на которые ссылаются, затем запросите их (два отдельных оператора SOQL), поместив их в карты Map<Id, TheType__c>, а затем просто используйте эти карты, чтобы получить требуемые значения для каждой записи Trigger.new, применяя свою логику. по мере необходимости.
 – 
Phil W
11 Июл 2021 в 01:56
Почему это должен быть триггер вершины? Похоже, что правило проверки будет работать, поскольку вы можете получить доступ к полям родительских объектов.
 – 
Kris Goncalves
11 Июл 2021 в 02:17

1 ответ

Лучший ответ
  1. Имеет смысл запрашивать только вставленные данные, связанные с кредитом, но вы запрашиваете все кредиты.
  2. Поскольку это перед вставкой, вы не можете запрашивать так, как у вас есть. Вставленные ссуды получают идентификаторы, назначенные только после вставки, что слишком поздно для того, что вы хотите сделать.

Измените триггер на:

trigger LoanTrigger on Loan__c (before insert) {
    Set<Id> bookIds = new Set<Id>();
    Set<Id> readerIds = new Set<Id>();

    // Find all unique referenced books and readers
    for (Loan__c loan : Trigger.new) {
        bookIds.add(loan.Book__c);
        readerIds.add(loan.Reader__c);
    }

    // Load the unique book and reader records so we have access to the subjects
    Map<Id, Book__c> booksById = new Map<Id, Book__c>(
        [SELECT Id, Subject__c FROM Book__c WHERE Id IN :bookIds]);
    Map<Id, Reader__c> readersById = new Map<Id, Reader__c>(
        [SELECT Id, Subject__c FROM Reader__c WHERE Id IN :readerIds]);

    // Check that the newly created loans have matching book and reader subjects
    for (Loan__c loan : Trigger.new) {
        if (booksById.get(loan.Book__c).Subject__c !=
            readersById.get(loan.Reader__c).Subject__c) {
            loan.addError('BOOK AND READER SUBJECTS MUST BE SAME');
        } 
    }
}

Обратите внимание, что я предположил, что поля Book и Reader являются MasterDetail и поэтому не могут быть нулевыми.

Это также не препятствует тому, чтобы ценности книги или читателя изменялись позже, так что действительные критерии кредита могут впоследствии и незаметно быть нарушены.

2
Phil W 11 Июл 2021 в 10:12
Спасибо, Фил. Это отлично работает
 – 
Hari Ha
11 Июл 2021 в 03:23