проблема при создании Case в триггере

проблема при создании Case в триггере

При создании нового контакта автоматически должен создаваться Case при помощи триггера. Case должен привязываться к новому контакту. Если контакт ссылается на аккаунт, тогда новый Case также должен ссылаться на этот аккаунт.

начало наверное такое, но как дальше?

trigger ContactTrigger on Contact (before insert){

List <String> emailAddresses = new List<String>();
for (Contact c : Trigger.new) {
emailAddresses .add(c.Email);
}

List <Contact> contacts = [SELECT Email From Contact WHERE Email IN :emailAddresses ];
Set<String> takenEmails = new Set<String>();

for(Contact pr : contacts){
takenEmails.add(pr.Email);
}

Map<String,Case> emailToCaseMap = new Map<String,Case>();
List<Contact> casesToUpdate = new List<Contact>();

...
}

где про это почитать?

Cool, ты лучше называй тему с каким-то смыслом. Например "проблема при создании Case в триггере"

Dmitry Shnyrev
Cool, ты лучше называй тему с каким-то смыслом. Например "проблема при создании Case в триггере"
поменял)

Смотрю на код и просто вообще не понимаю что ты в каждой строчке хочешь сделать
Ты можешь проговорить ход своих мыслей сначала без кода?

Dmitry Shnyrev
Смотрю на код и просто вообще не понимаю что ты в каждой строчке хочешь сделать
Ты можешь проговорить ход своих мыслей сначала без кода?

Ход моих мыслей навеян вот этой статьей
https://developer.salesforce.com/page/Autocreating_Contacts_From_Web_To_Case

List <String> emailAddresses = new List<String>();
for (Contact c : Trigger.new) {
emailAddresses .add(c.Email);
}

List <Contact> contacts = [SELECT Email From Contact WHERE Email IN :emailAddresses ];
Set<String> takenEmails = new Set<String>();

for(Contact pr : contacts){
takenEmails.add(pr.Email);
}

в лист для емэйл кладем все емэйлы, что пришли в тригер.
делаем лист контактов, в которых есть емэйл.

делаем из них сет, чтобы были на выходе были уникальные записи (из всех что пришли в тригер)

Ничего что там триггер на Case и логика отличается от твоей?

Dmitry Shnyrev
Ничего что там триггер на Case и логика отличается от твоей?

в статье - я заметил что на кейс. вот и спрашиваю как наоборот сделать)
там Autocreating Contacts From Web To Case
а мне наоборот надо.если у меня все не так - то как?
или где про это почитать

Забудь про этот пример.

Попробуй проговорить логику словами без кода.

Начни с "в триггер приходит 10 контактов". Что дальше?

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

Dmitry Shnyrev
Забудь про этот пример.

Попробуй проговорить логику словами без кода.

Начни с "в триггер приходит 10 контактов". Что дальше?

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


ну вот все в итоге попадут в set если email не повторяется

cool
Dmitry Shnyrev
Забудь про этот пример.

Попробуй проговорить логику словами без кода.

Начни с "в триггер приходит 10 контактов". Что дальше?

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


ну вот все в итоге попадут в set если email не повторяется

List <String> emailAddresses  = new List<String>();    

for (Contact c : Trigger.new) {
emailAddresses .add(c.Email);
}

List <Contact> contacts = [SELECT Email From Contact WHERE Email IN :emailAddresses ];
Set<String> takenEmails = new Set<String>();

for(Contact pr : contacts){
takenEmails.add(pr.Email);
}

for (Contact c : Trigger.new){
if(takenEmails.contains(c.Email) == true)
{
c.Email.addError('Contact with this email is already created');
}
}

При чем здесь вообще Email?
Case привязывается к Contact и Account по Id
https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_objects_case.htm
Почему я и говорю что ссылка не подходит чтобы оттуда черпать знания.

Dmitry Shnyrev
При чем здесь вообще Email?
Case привязывается к Contact и Account по Id
https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_objects_case.htm
Почему я и говорю что ссылка не подходит чтобы оттуда черпать знания.

эта часть кода для проверки на "невставляемость" одного и того же контакта, для проверки на уникальность.Скинул то что есть на данный момент

А, ну теперь понятно.
А то спрашиваешь про одно, код приводишь для другого.

Так в чем загвоздка с Case?

Dmitry Shnyrev
Так в чем загвоздка с Case?

так а так хоть правильная проверка на "уникальность"?

загвоздка в том что не знаю как подойти к этой задача, в трэлхэеде не нашел, то что скинул ссылку- не совсем то, но мне кажется что как то так и нужно делать.

я так понимаю в процес билдере такое сейчас делается, но мне нужен тригер

cool
загвоздка в том что не знаю как подойти к этой задача, в трэлхэеде не нашел, то что скинул ссылку- не совсем то, но мне кажется что как то так и нужно делать.

Надо не пример искать, а просто внимательно и вдумчиво почитать доку про написание тригеров. Тогда и станет ясно как реализовать задачу.
На угадывании далеко не уедешь.

Apex Developer Guide - Triggers
Trailhead - Get Started with Apex Triggers

3-4 часа чтения и достаточно знаний для последующего обсуждения на собеседовании при обсуждении тестового задания.

Да, проверка на уникально отличная.

Вот с вопросом про Cases проблема. Помочь исправить проблему, подсказать правильно или нет еще тут помогут, но написать код увы.

В двух словах - тебе просто надо в триггере пробежаться по всем контактам и создать для каждого новый Case с правильно заполненными полями. Все остальное нюансы реализации.

А в чем, собственно, проблема? Я ни одной строчки с объектом Case не увидел. Ни список для insert. Ни самого insert кейсов. Как ты хочешь создавать кейсы не создавая их в коде?

Dmitry Shnyrev
При чем здесь вообще Email?
Case привязывается к Contact и Account по Id
https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_objects_case.htm
Почему я и говорю что ссылка не подходит чтобы оттуда черпать знания.

Скажи, а как понять по этой таблице, с чем связан Case и что он по Id связан с Contact и Account

кажется это
http://prntscr.com/iqjnng
http://prntscr.com/iqjo23

Да, это.
Почитай про Object Relationships
Особенно обрати внимание на порядок наименования полей и их использование в коде.
Как бы без этих знаний даже за код садиться нельзя.

Dmitry Shnyrev
Object Relationships
Особенно обрати внимание на порядо

List<Contact> needAccounts = new List<Contact>();

for (Contact c : trigger.new) {
if (String.isBlank(c.accountid)) {
needAccounts.add(c);
}
}

if (needAccounts.size() > 0) {
List<Case> newAccounts = new List<Case>();
Map<String,Contact> contactsByNameKeys = new Map<String,Contact>();
for (Contact c : needAccounts) {
Case a = new Case(Status = 'Working', Origin ='New Contact');
newAccounts.add(a);
}
insert newAccounts;
}

что то такое должно быть

Да. Только при создании нового кейса на 12 строчке, тебе надо указывать контакт, к которому привязать кейс. А так, он у тебя не привязан.

Andrii Muzychuk
Да. Только при создании нового кейса на 12 строчке, тебе надо указывать контакт, к которому привязать кейс. А так, он у тебя не привязан.

Case a = new Case(Status = 'Working', Origin ='New Contact', AccountId = c.AccountId);

Блин, все не так.
Во первых разберись с названиями переменных.
Что это такое?
List<Case> newAccounts
Второе, тебе не нужны никакие needAccounts

Опять повторяю - надо сначала понять что ты хочешь сделать простым русским языком, а потом это переводить в код. А так у тебя просто куча бессмысленных строчек кода.

Ты ж писал, что к Контакту надо привязать? Зачем тебе AccountId? Он, если не ошибаюсь, автоматом пропишется из Контакта.

Даю последнюю подсказку
эта задача делается в 3-5 строчек кода (в зависимости от оформления)
и эти строчки у тебя уже есть в твоем примере. С кучей других бесполезных.

Dmitry Shnyrev
азберись с названиями переменных.
Что это такое?

это из примера с нета)
с названиями переменных косяк

Как ты собираешься вообще работать?
Эта задача вообще не задача и делается в 3 строчки кода. В реальных проектах тысячи строк кода и логика которую надо будет переваривать по нескольку часов.

Мне кажется надо пока отложить тестовое задание если это оно и начать с того что потратить 3-6 месяцев на прохождение Trailhead.

Дима, тут не вопрос в трэйлхэдах. Трэйлхэды не помогут. Нужен человек, который будет помогать, подсказывать и направлять.

Человек который помогает конечно должен быть.
Но помогать можно на основании какой-то базы.
Документацию даже на начальном этапе надо знать чтобы общаться на одном уровне и оперировать общими понятиями.
У меня было много попыток помочь людям и я понял одну простую истину:
Если спрашивают ПОЧЕМУ НЕ РАБОТАЕТ еще можно помочь, если спрашивают КАК СДЕЛАТЬ то все намного хуже
Второй вариант еще можно допустить если такой вопрос относится к какой-то крайне сложной логике которая нигде незадокументирована. Обычно вопросы КАК СДЕЛАТЬ могут задавать гуру с 10 летним опытом отправляя все сообщество в затуп. Но в остальном это непростительно!

К примеру относительно себя, я начал задавать вопросы другим программистам на форумах тольк когда просидел года 2 над тупыми туториалами из интернета на тему "Как сделать сайт на PHP и MYSQL". У меня уже за плечами были корявые но работающие сайты. И только потом я взялся за первое тестовое задание.

Andrii Muzychuk
Ты ж писал, что к Контакту надо привязать? Зачем тебе AccountId? Он, если не ошибаюсь, автоматом пропишется из Контакта.

вот задание
"При создании нового контакта автоматически должен создаваться Case при помощи триггера. Case должен привязываться к новому контакту. Если контакт ссылается на аккаунт, тогда новый Case также должен ссылаться на этот аккаунт.
Поле Status у нового Case должно принимать значение ‘Working’, а поле Case Origin должно принимать значение ‘New Contact’.
Поле Owner у Case должен быть таким же как Owner у аккаунта, на которого ссылается контакт."

и вот что получилось

List<Contact> contactList = new List<Contact>();

for (Contact c : trigger.new) {
contactList.add(c);
}

if (contactList.size() > 0) {
List<Case> newCases = new List<Case>();
for (Contact c : contactList) {
if((String.isBlank(c.AccountId))){
Case a = new Case(Status = 'Working', Origin ='New Contact');
newCases.add(a);
}
else{
Case a = new Case(Status = 'Working', Origin ='New Contact', OwnerId = c.OwnerId, ContactId = c.AccountId );
newCases.add(a);
}
}
insert newCases;
}

cool, отдохни сегодня от Арех. У тебя такая каша в голове. Ты вообще не соображаешь, что ты пишешь. Ты бездумно пишешь "что-то". Давай завтра еще раз попробуешь.
Если не готов сегодня отдыхать, я тебе советую, в таком случае, создать вручную Аккаунт, Контак у этого Аккаунта, и птм Кейс. И посмотри, какие поля у Кейса какими значениями заполнены. Сопоставь Idшники. Пройди тот путь, который надо в триггере руками.

Andrii Muzychuk
cool, отдохни сегодня от Арех. У тебя такая каша в голове. Ты вообще не соображаешь, что ты пишешь. Ты бездумно пишешь "что-то". Давай завтра еще раз попробуешь.
Если не готов сегодня отдыхать, я тебе советую, в таком случае, создать вручную Аккаунт, Контак у этого Аккаунта, и птм Кейс. И посмотри, какие поля у Кейса какими значениями заполнены. Сопоставь Idшники. Пройди тот путь, который надо в триггере руками.

ладно,спасибо. уже действительно каша.

cool
При создании нового контакта автоматически должен создаваться Case при помощи триггера. Case должен привязываться к новому контакту. Если контакт ссылается на аккаунт, тогда новый Case также должен ссылаться на этот аккаунт.

начало наверное такое, но как дальше?

trigger ContactTrigger on Contact (before insert){

List <String> emailAddresses = new List<String>();
for (Contact c : Trigger.new) {
emailAddresses .add(c.Email);
}

List <Contact> contacts = [SELECT Email From Contact WHERE Email IN :emailAddresses ];
Set<String> takenEmails = new Set<String>();

for(Contact pr : contacts){
takenEmails.add(pr.Email);
}

Map<String,Case> emailToCaseMap = new Map<String,Case>();
List<Contact> casesToUpdate = new List<Contact>();

...
}

где про это почитать?

Поскольку нам нужен ContactId поэтому должен быть after insert. Account должен подставится сам с контакта
Как-то так

trigger ContactTrigger on Contact (after insert){

List<Case> cases = new List<Case>();
Set<Id> accIds = new Set<Id>();
for (Contact c : Trigger.newMap.values()) {
accIds.add(c.AccountId);
}
Map<Id,Account> mapIdToAcc = new Map<Id,Account>([SELECT Id,OwnerId FROM Account WHERE Id IN :accIds]);
for (Contact c : Trigger.newMap.values()) {
cases.add(new Case(ContactId=c.Id, OwnerId=mapIdToAcc.get(c.AccountId).OwnerId));
}
insert cases;
}

Сразу видно, кто не хочет, что б появлялись думающие сами разработчики... Ну тоже правильно - меньше конкуренция...

camamber
Как-то так

Взял и спалил!

Dmitry Shnyrev
camamber
Как-то так

Взял и спалил!

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

он как-то иначе сделал:)

Можно дать рыбу, а можно удочку. Ты предпочитаешь рыбу?

camamber
cool
При создании нового контакта автоматически должен создаваться Case при помощи триггера. Case должен привязываться к новому контакту. Если контакт ссылается на аккаунт, тогда новый Case также должен ссылаться на этот аккаунт.

начало наверное такое, но как дальше?

trigger ContactTrigger on Contact (before insert){

List <String> emailAddresses = new List<String>();
for (Contact c : Trigger.new) {
emailAddresses .add(c.Email);
}

List <Contact> contacts = [SELECT Email From Contact WHERE Email IN :emailAddresses ];
Set<String> takenEmails = new Set<String>();

for(Contact pr : contacts){
takenEmails.add(pr.Email);
}

Map<String,Case> emailToCaseMap = new Map<String,Case>();
List<Contact> casesToUpdate = new List<Contact>();

...
}

где про это почитать?

Поскольку нам нужен ContactId поэтому должен быть after insert. Account должен подставится сам с контакта
Как-то так

trigger ContactTrigger on Contact (after insert){

List<Case> cases = new List<Case>();
Set<Id> accIds = new Set<Id>();
for (Contact c : Trigger.newMap.values()) {
accIds.add(c.AccountId);
}
Map<Id,Account> mapIdToAcc = new Map<Id,Account>([SELECT Id,OwnerId FROM Account WHERE Id IN :accIds]);
for (Contact c : Trigger.newMap.values()) {
cases.add(new Case(ContactId=c.Id, OwnerId=mapIdToAcc.get(c.AccountId).OwnerId));
}
insert cases;
}

Спасибо, а если другая часть кода триггера идет before insert, как быть?

Andrii Muzychuk
Можно дать рыбу, а можно удочку. Ты предпочитаешь рыбу?

удочку!
но и от рыбы никто не откажется

cool
camamber
cool
При создании нового контакта автоматически должен создаваться Case при помощи триггера. Case должен привязываться к новому контакту. Если контакт ссылается на аккаунт, тогда новый Case также должен ссылаться на этот аккаунт.

начало наверное такое, но как дальше?

trigger ContactTrigger on Contact (before insert){

List <String> emailAddresses = new List<String>();
for (Contact c : Trigger.new) {
emailAddresses .add(c.Email);
}

List <Contact> contacts = [SELECT Email From Contact WHERE Email IN :emailAddresses ];
Set<String> takenEmails = new Set<String>();

for(Contact pr : contacts){
takenEmails.add(pr.Email);
}

Map<String,Case> emailToCaseMap = new Map<String,Case>();
List<Contact> casesToUpdate = new List<Contact>();

...
}

где про это почитать?

Поскольку нам нужен ContactId поэтому должен быть after insert. Account должен подставится сам с контакта
Как-то так

trigger ContactTrigger on Contact (after insert){

List<Case> cases = new List<Case>();
Set<Id> accIds = new Set<Id>();
for (Contact c : Trigger.newMap.values()) {
accIds.add(c.AccountId);
}
Map<Id,Account> mapIdToAcc = new Map<Id,Account>([SELECT Id,OwnerId FROM Account WHERE Id IN :accIds]);
for (Contact c : Trigger.newMap.values()) {
cases.add(new Case(ContactId=c.Id, OwnerId=mapIdToAcc.get(c.AccountId).OwnerId));
}
insert cases;
}

Спасибо, а если другая часть кода триггера идет before insert, как быть?

Какая часть? Что там происходит?

camamber
cool
camamber
cool
При создании нового контакта автоматически должен создаваться Case при помощи триггера. Case должен привязываться к новому контакту. Если контакт ссылается на аккаунт, тогда новый Case также должен ссылаться на этот аккаунт.

начало наверное такое, но как дальше?

trigger ContactTrigger on Contact (before insert){

List <String> emailAddresses = new List<String>();
for (Contact c : Trigger.new) {
emailAddresses .add(c.Email);
}

List <Contact> contacts = [SELECT Email From Contact WHERE Email IN :emailAddresses ];
Set<String> takenEmails = new Set<String>();

for(Contact pr : contacts){
takenEmails.add(pr.Email);
}

Map<String,Case> emailToCaseMap = new Map<String,Case>();
List<Contact> casesToUpdate = new List<Contact>();

...
}

где про это почитать?

Поскольку нам нужен ContactId поэтому должен быть after insert. Account должен подставится сам с контакта
Как-то так

trigger ContactTrigger on Contact (after insert){

List<Case> cases = new List<Case>();
Set<Id> accIds = new Set<Id>();
for (Contact c : Trigger.newMap.values()) {
accIds.add(c.AccountId);
}
Map<Id,Account> mapIdToAcc = new Map<Id,Account>([SELECT Id,OwnerId FROM Account WHERE Id IN :accIds]);
for (Contact c : Trigger.newMap.values()) {
cases.add(new Case(ContactId=c.Id, OwnerId=mapIdToAcc.get(c.AccountId).OwnerId));
}
insert cases;
}

Спасибо, а если другая часть кода триггера идет before insert, как быть?

Какая часть? Что там происходит?

проверка на уникальность добавления записи

List <String> emailAddresses  = new List<String>();    

for (Contact c : Trigger.new) {
emailAddresses .add(c.Email);
}

List <Contact> contacts = [SELECT Email From Contact WHERE Email IN :emailAddresses ];
Set<String> takenEmails = new Set<String>();

for(Contact pr : contacts){
takenEmails.add(pr.Email);
}
for (Contact c : Trigger.new){
if(takenEmails.contains(c.Email) == true)
{
c.Email.addError('Contact with this email is already created');
}
}

for (Contact c : Trigger.new) {
if (c.Email == null) {
c.Email.addError('Please enter email');
}
}
for (Contact c : Trigger.new) {
if (c.LastName == null) {
c.Email.addError('Please enter Last Name');
}
}

cool
camamber
cool
camamber
cool
При создании нового контакта автоматически должен создаваться Case при помощи триггера. Case должен привязываться к новому контакту. Если контакт ссылается на аккаунт, тогда новый Case также должен ссылаться на этот аккаунт.

начало наверное такое, но как дальше?

trigger ContactTrigger on Contact (before insert){

List <String> emailAddresses = new List<String>();
for (Contact c : Trigger.new) {
emailAddresses .add(c.Email);
}

List <Contact> contacts = [SELECT Email From Contact WHERE Email IN :emailAddresses ];
Set<String> takenEmails = new Set<String>();

for(Contact pr : contacts){
takenEmails.add(pr.Email);
}

Map<String,Case> emailToCaseMap = new Map<String,Case>();
List<Contact> casesToUpdate = new List<Contact>();

...
}

где про это почитать?

Поскольку нам нужен ContactId поэтому должен быть after insert. Account должен подставится сам с контакта
Как-то так

trigger ContactTrigger on Contact (after insert){

List<Case> cases = new List<Case>();
Set<Id> accIds = new Set<Id>();
for (Contact c : Trigger.newMap.values()) {
accIds.add(c.AccountId);
}
Map<Id,Account> mapIdToAcc = new Map<Id,Account>([SELECT Id,OwnerId FROM Account WHERE Id IN :accIds]);
for (Contact c : Trigger.newMap.values()) {
cases.add(new Case(ContactId=c.Id, OwnerId=mapIdToAcc.get(c.AccountId).OwnerId));
}
insert cases;
}

Спасибо, а если другая часть кода триггера идет before insert, как быть?

Какая часть? Что там происходит?

проверка на уникальность добавления записи

List <String> emailAddresses  = new List<String>();    

for (Contact c : Trigger.new) {
emailAddresses .add(c.Email);
}

List <Contact> contacts = [SELECT Email From Contact WHERE Email IN :emailAddresses ];
Set<String> takenEmails = new Set<String>();

for(Contact pr : contacts){
takenEmails.add(pr.Email);
}
for (Contact c : Trigger.new){
if(takenEmails.contains(c.Email) == true)
{
c.Email.addError('Contact with this email is already created');
}
}

for (Contact c : Trigger.new) {
if (c.Email == null) {
c.Email.addError('Please enter email');
}
}
for (Contact c : Trigger.new) {
if (c.LastName == null) {
c.Email.addError('Please enter Last Name');
}
}

И в чем проблема?

camamber
cool
camamber
cool
camamber
cool
При создании нового контакта автоматически должен создаваться Case при помощи триггера. Case должен привязываться к новому контакту. Если контакт ссылается на аккаунт, тогда новый Case также должен ссылаться на этот аккаунт.

начало наверное такое, но как дальше?

trigger ContactTrigger on Contact (before insert){

List <String> emailAddresses = new List<String>();
for (Contact c : Trigger.new) {
emailAddresses .add(c.Email);
}

List <Contact> contacts = [SELECT Email From Contact WHERE Email IN :emailAddresses ];
Set<String> takenEmails = new Set<String>();

for(Contact pr : contacts){
takenEmails.add(pr.Email);
}

Map<String,Case> emailToCaseMap = new Map<String,Case>();
List<Contact> casesToUpdate = new List<Contact>();

...
}

где про это почитать?

Поскольку нам нужен ContactId поэтому должен быть after insert. Account должен подставится сам с контакта
Как-то так

trigger ContactTrigger on Contact (after insert){

List<Case> cases = new List<Case>();
Set<Id> accIds = new Set<Id>();
for (Contact c : Trigger.newMap.values()) {
accIds.add(c.AccountId);
}
Map<Id,Account> mapIdToAcc = new Map<Id,Account>([SELECT Id,OwnerId FROM Account WHERE Id IN :accIds]);
for (Contact c : Trigger.newMap.values()) {
cases.add(new Case(ContactId=c.Id, OwnerId=mapIdToAcc.get(c.AccountId).OwnerId));
}
insert cases;
}

Спасибо, а если другая часть кода триггера идет before insert, как быть?

Какая часть? Что там происходит?

проверка на уникальность добавления записи

List <String> emailAddresses  = new List<String>();    

for (Contact c : Trigger.new) {
emailAddresses .add(c.Email);
}

List <Contact> contacts = [SELECT Email From Contact WHERE Email IN :emailAddresses ];
Set<String> takenEmails = new Set<String>();

for(Contact pr : contacts){
takenEmails.add(pr.Email);
}
for (Contact c : Trigger.new){
if(takenEmails.contains(c.Email) == true)
{
c.Email.addError('Contact with this email is already created');
}
}

for (Contact c : Trigger.new) {
if (c.Email == null) {
c.Email.addError('Please enter email');
}
}
for (Contact c : Trigger.new) {
if (c.LastName == null) {
c.Email.addError('Please enter Last Name');
}
}

И в чем проблема?


я думал на уникальность надо проверять до того как insert.
я так понял надо сделать его (before insert, after insert) и будет гуд

cool
я думал на уникальность надо проверять до того как insert

Так код и проверяет до того как insert. Или я что-то не так понял?

camamber
cool
я думал на уникальность надо проверять до того как insert

Так код и проверяет до того как insert. Или я что-то не так понял?
ну да, мой кусок триггера - before insert, твой after insert

cool
ну да, мой кусок триггера - before insert, твой after insert

Так в чем проблема? Что не работает?

camamber
cool
ну да, мой кусок триггера - before insert, твой after insert

Так в чем проблема? Что не работает?

я пока не пробовал.просто спрашивал пока что

camamber
Так в чем проблема? Что не работает?

camamber теперь ты на нашей стороне ?

Dmitry Shnyrev
camamber
Так в чем проблема? Что не работает?

camamber теперь ты на нашей стороне ?

из-за вот этого?

A map of IDs to the new versions of the sObject records.
This map is only available in before update, after insert, after update, and after undelete triggers.

cool
но и от рыбы никто не откажется

Рыба приводит к деградации. Потом на удочку и смотреть не хочется.
Всё потому что наш мозг это очень энергоэффективная система и никогда не потратит лишнюю энергию, если можно не тратить.

Developer
cool
но и от рыбы никто не откажется

Рыба приводит к деградации. Потом на удочку и смотреть не хочется.
Всё потому что наш мозг это очень энергоэффективная система и никогда не потратит лишнюю энергиюесли можно не тратить.


ну вы тут прямо развели.так или иначе сижу разбираюсь, с этой "рыбой"

Чтобы эффективно рыбачить надо изучить все азы рыбалки сначала а потом покупать удочку и идти за рыбой

Dmitry Shnyrev
Чтобы эффективно рыбачить надо изучить все азы рыбалки сначала а потом покупать удочку и идти за рыбой :D
а я предпочел сразу рыбачить и рыбку взять с собой.
но что-то рыбка выдает

ContactTrigger: execution of AfterInsert caused by: System.NullPointerException: Attempt to de-reference a null object Trigger.ContactTrigger:

Это самая классическая ошибка в любом языке!!!
Старый добрый NullPointerException !!!

Dmitry Shnyrev
Это самая классическая ошибка в любом языке!!!
Старый добрый NullPointerException !!!

я очень рад такому событию!:)
где то тут ошибка OwnerId=mapIdToAcc.get(c.AccountId).OwnerId

camamber
где то тут ошибка OwnerId=mapIdToAcc.get(c.AccountId).OwnerId

где то тут ошибка OwnerId=mapIdToAcc.get(c.AccountId).OwnerId

ContactTrigger: execution of AfterInsert caused by: System.NullPointerException: Attempt to de-reference a null object Trigger.ContactTrigger:

http://career.success-craft.com/courses

Может вариант начать с этого?

Дима, азы в любой сфере лучше постигать с учителем.

cool, давай с другой стороны зайдем. Скинь нам код теста на это задание. Как ты собираешься проверять работоспособность своего кода?

Dmitry Shnyrev
http://career.success-craft.com/courses

Может вариант начать с этого?


Контакты - career.successcraft@gmail.com
Фэйспалм... Где у тебя такой смайл, Дима?

Да, со смайлами худо.
Если сильно хочется - есть хак
можно просто ссылкой на внешнюю картинку добавить

Вот отсюда взять
https://support.skype.com/en/faq/FA12330/what-is-the-full-list-of-emoticons

!!! только убрать все что после расширения файла.

Andrii Muzychuk
Дима, азы в любой сфере лучше постигать с учителем.

cool, давай с другой стороны зайдем. Скинь нам код теста на это задание. Как ты собираешься проверять работоспособность своего кода?


я пока тесты не писал

Ну и развели вы тут...

Andrii Muzychuk
Дима, азы в любой сфере лучше постигать с учителем.

cool, давай с другой стороны зайдем. Скинь нам код теста на это задание. Как ты собираешься проверять работоспособность своего кода?


дошло дело до тестов...

@isTest public class ContactTriggerTest {

@isTest static void ContactTriggerTest() {
test.startTest();
List<Contact> cnt = new List<Contact>();
Contact a = new Contact(FirstName = 'Asdnn', LastName = 'kiki', Email = 'sgff@wfgf.er', Contact_Level__c = 'Primary', AccountId = '0017F00000XQ8DxQAL');
cnt.add(a);
insert cnt;
test.stopTest();
}

И это у тебя работает?

Dmitry Shnyrev
И это у тебя работает?

нет. опять nullPoiner..
но я также на вью подаю такой же контакт - работает. почему тут нет?

Ладно, тебе простительно.
Ошибки. Исправляй.

Тесты не видят реальные данные (пока не попросишь отдельно). То есть тебя нет этого Account ID. Account как и любые другие данные надо создавать. Тесты запускаются с пустой базой.

Собственно отсюда вытекает что нельзя ни к коем случае использовать хардкодные Id (0017F00000XQ8DxQAL). Ты должен достать этот Id из базы.

Ты еще не разобрался NullPointerException?
Брось все и разбирайся пока не начнешь с закрытыми глазами понимать в чем причина ошибки.

Dmitry Shnyrev
Ты еще не разобрался NullPointerException?
Брось все и разбирайся пока не начнешь с закрытыми глазами понимать в чем причина ошибки.

С той что в триггере я вроде понял.

Dmitry Shnyrev
Ладно, тебе простительно.
Ошибки. Исправляй.

Тесты не видят реальные данные (пока не попросишь отдельно). То есть тебя нет этого Account ID. Account как и любые другие данные надо создавать. Тесты запускаются с пустой базой.

Собственно отсюда вытекает что нельзя ни к коем случае использовать хардкодные Id (0017F00000XQ8DxQAL). Ты должен достать этот Id из базы.

@isTest (SeeAllData = true) public class ContactTriggerTest {



@isTest static void ContactTriggerTest() {

Account acc = new Account(Name='TestAccount');
insert acc;

List<Contact> cnt = new List<Contact>();
Contact a = new Contact(FirstName = 'Asdnn', LastName = 'kiki', Email = 'sgff@wfgf.er', Contact_Level__c = 'Primary', AccountId = acc.Id);
Contact b = new Contact(FirstName = 'Asdnn', LastName = 'kiki', Email = 'sgff@wfgf.er', Contact_Level__c = 'Secondary', AccountId = acc.Id);
Contact c = new Contact(FirstName = 'Asdnn', LastName = 'kiki', Email = 'sgff@wfgf.er', Contact_Level__c = 'Tertiary', AccountId = acc.Id);
cnt.add(a);
cnt.add(b);
cnt.add(c);
insert cnt;

}
}

такого плана?

Ага. Только теперь убирай (SeeAllData = true)

Хорошо. Ты создал Контак. А теперь надо проверить, что правильная Задача была создана для Контакта.

да, тест норм.

Андрей, не "Задача" а Case
Не вводи в заблуждение с этими русскими эквивалентами.

Оу. Та я про Task думал :-) Перепутал ;-) Я даже не знаю, как Case СФ на русский переводит.

Отсюда вытекает правило!!!
Вся разработка, все общение даже среди русских разработчиков исключительно с помощью английских понятий как в оригинальной документации.
Даже в "русских" проектах не должно быть ни слова (ни даже буквы) на русском. Вся руссификация делается с помощью Translation Workbench.
А то меня сразу передергивает когда в исходном коде я вижу русские строки. Это касается и других языков.

Andrii Muzychuk
(SeeAllData = true)

убрал, теперь кейс создался только в 1 случае.
а почему нельзя (SeeAllData = true) использовать?

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

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

так?

@isTest static void ContactTriggerTest() {


Account acc = new Account(Name='TestAccount');
insert acc;

List<Contact> cnt = new List<Contact>();
Contact a = new Contact(FirstName = 'Asdnn', LastName = 'kiki', Email = 'sgff@wfgf.er', Contact_Level__c = 'Primary', AccountId = acc.Id);
Contact b = new Contact(FirstName = 'Asdnn', LastName = 'kiki', Email = 'sgff@wfgf.er', Contact_Level__c = 'Secondary', AccountId = acc.Id);
Contact c = new Contact(FirstName = 'Asdnn', LastName = 'kiki', Email = 'sgff@wfgf.er', Contact_Level__c = 'Tertiary', AccountId = acc.Id);
Contact d = new Contact(FirstName = 'Asdnn', LastName = 'kiki', Email = 'sgff@wfgf.er', AccountId = acc.Id);
cnt.add(a);
cnt.add(b);
cnt.add(c);
cnt.add(d);
insert cnt;

List <Case> cass = [SELECT Id, OwnerID, Status, Origin, Priority FROM Case ];
Case aaa = cass.get(0);
Case bbb = cass.get(0);
Case ccc = cass.get(0);
Case ddd = cass.get(0);
System.debug(aaa.Priority == 'High');
System.assert(aaa.Priority == 'High', true);
System.assert(bbb.Priority == 'High', true);
System.assert(ccc.Priority == 'High', true);
System.assert(ddd.Priority == 'High', true);
}
}

Почти.
Только в переменные aaa, bbb, ccc, ddd ты вычитываешь один и тот же Case.
Помимо Priority тебе надо проверить, что у Case задан правильный ContactId и AccountId (и какие-то еще поля, которые надо проставить).

System.assertEquals('High', aaa.Priority);

Andrii Muzychuk
Почти.
Только в переменные aaa, bbb, ccc, ddd ты вычитываешь один и тот же Case.
Помимо Priority тебе надо проверить, что у Case задан правильный ContactId и AccountId (и какие-то еще поля, которые надо проставить).

System.assertEquals('High', aaa.Priority);

ой , ну да, тут 1,2,3,4
Case bbb = cass.get(0);
Case ccc = cass.get(0);
Case ddd = cass.get(0);

cool
Andrii Muzychuk
Почти.
Только в переменные aaa, bbb, ccc, ddd ты вычитываешь один и тот же Case.
Помимо Priority тебе надо проверить, что у Case задан правильный ContactId и AccountId (и какие-то еще поля, которые надо проставить).

System.assertEquals('High', aaa.Priority);

ой , ну да, тут 1,2,3,4
Case bbb = cass.get(0);
Case ccc = cass.get(0);
Case ddd = cass.get(0);

@isTest  public class ContactTriggerTest {



@isTest static void ContactTriggerTest() {


Account acc = new Account(Name='TestAccount');
insert acc;

List<Contact> cnt = new List<Contact>();
Contact a = new Contact(FirstName = 'Asdnn', LastName = 'kiki', Email = 'sgff@wfgf.er', Contact_Level__c = 'Primary', AccountId = acc.Id);
Contact b = new Contact(FirstName = 'Asdnn', LastName = 'kiki', Email = 'sgff@wfgf.er', Contact_Level__c = 'Secondary', AccountId = acc.Id);
Contact c = new Contact(FirstName = 'Asdnn', LastName = 'kiki', Email = 'sgff@wfgf.er', Contact_Level__c = 'Tertiary', AccountId = acc.Id);
Contact d = new Contact(FirstName = 'Asdnn', LastName = 'kiki', Email = 'sgff@wfgf.er', AccountId = acc.Id);
cnt.add(a);
cnt.add(b);
cnt.add(c);
cnt.add(d);
insert cnt;

List <Case> cass = [SELECT Id, ContactId, AccountId, OwnerID, Status, Origin, Priority FROM Case ];
Case aaa = cass.get(0);
Case bbb = cass.get(1);
Case ccc = cass.get(2);
Case ddd = cass.get(3);

System.assert(aaa.Priority == 'High', true);
System.assert(bbb.Priority == 'Medium', true);
System.assert(ccc.Priority == 'Low', true);
System.assert(ddd.Priority == 'Medium', true);

System.assert(aaa.Status == 'Working');
System.assert(aaa.Origin == 'New Contact');

System.assert(a.AccountId == aaa.AccountId,true);
System.assert(b.AccountId == bbb.AccountId,true);
System.assert(c.AccountId == ccc.AccountId,true);
System.assert(d.AccountId == ddd.AccountId,true);

System.assert(aaa.ContactId == a.Id);
System.assert(bbb.ContactId == b.Id);
System.assert(ccc.ContactId == c.Id);
System.assert(ddd.ContactId == d.Id);

}
}

и еще вопрос, есть в контролере удаление из бд

public void deleterecord(){	


delete Database.query('SELECT ID From Contact WHERE Id = :myID');
}


}

@isTest static void deleterecord()

{
Account acc = new Account(Name='TestAccount');
insert acc;
Contact contact = new Contact(FirstName = 'Asdnn', LastName = 'kiki', Email = 'sgff@wfgf.er', Contact_Level__c = 'Primary', AccountId = acc.Id);
insert contact;
Test.StartTest();
ContactPageController controller = new ContactPageController();
controller.myID = contact.Id;
controller.deleterecord();
System.assert(contact.IsDeleted, true);
Test.StopTest();
}

что не так с тестом?

0
ты серьзно предалаешь нам отвечать на вопросы что не так с тестом? ну во первых с ним все не так. Если у тебя есть конкретные вопросы, стоит задавать их.

1

cool
System.assert(contact.IsDeleted, true);

https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_methods_system_system.htm

2 каким боком в твоем тесте должно заполнится на контакте поле IsDeleted?

Проблема в тесте в том что ты опять взял код и скопипастил не понимаю что он делает.

Поле IsDeleted конечно есть и даже вроде имеет какой-то похожий смысл

"Indicates whether the object has been moved to the Recycle Bin (true) or not (false). Label is Deleted."

Но блин, чет я не видел чтобы кто-то так делал.

А если включить мозги и применить логику, то вот что можно получить:

Если удалить объект из базы с помощью DML операции в методе deleterecord (кстати которая тоже написана крайне неприятным для разработчика виде) то по логике в базе этой записи не должно больше быть. Теперь эту логическую цепочку надо просто перевести в код в тесте.

Dmitry Shnyrev
Проблема в тесте в том что ты опять взял код и скопипастил не понимаю что он делает.

Поле IsDeleted конечно есть и даже вроде имеет какой-то похожий смысл

"Indicates whether the object has been moved to the Recycle Bin (true) or not (false). Label is Deleted."

Но блин, чет я не видел чтобы кто-то так делал.

А если включить мозги и применить логику, то вот что можно получить:

Если удалить объект из базы с помощью DML операции в методе deleterecord (кстати которая тоже написана крайне неприятным для разработчика виде) то по логике в базе этой записи не должно больше быть. Теперь эту логическую цепочку надо просто перевести в код в тесте.

вот весь метод целиком

public void deleterecord(){	

try{
delete Database.query('SELECT ID From Contact WHERE Id = :myID');
}
catch (Exception e){
ApexPages.Message myMsg = new ApexPages.Message(ApexPages.Severity.FATAL,'Your attempt to delete thiw row and it could not be completed because it is associated with some cases');
ApexPages.addMessage(myMsg);
}
SearchContact();

}

@isTest static void deleterecord()

{
Account acc = new Account(Name='TestAccount');
insert acc;
Contact contact = new Contact(FirstName = 'Asdnn', LastName = 'kiki', Email = 'sgff@wfgf.er', Contact_Level__c = 'Primary', AccountId = acc.Id);
insert contact;
Test.StartTest();
System.debug([select id from contact]); //здесь 1 штука есть
ContactPageController controller = new ContactPageController();
controller.myID = contact.Id;
controller.deleterecord();//удалили
System.debug([select id from contact]);//все равно 1 штука осталась!!!


Test.StopTest();
}

Теперь тест выглядит красивее!
Запись (Contact) не удаляется
Значит ищи проблему в ContactPageController

cool
//все равно 1 штука осталась!!!

cool
//удалили

сомневаюсь

Maxim Elets
cool
//все равно 1 штука осталась!!!

cool
//удалили

сомневаюсь
так вот почему так не работает?

Dmitry Shnyrev
Теперь тест выглядит красивее!
Запись (Contact) не удаляется
Значит ищи проблему в ContactPageController

Дело в том что контроллер работает, но конструкция типа

ContactPageController controller = new ContactPageController(); 

controller.myID = contact.Id;
controller.deleterecord();

или

ContactPageController controller = new ContactPageController(); 

controller.insertRecord();

не работает.что может быть не так?

Так сложно сказать что у тебя не работает.

Попробуй во первых убрать
try

catch (Exception e){...}

Возможно в тесте у тебя какой-то exception выпадает, а ты его успешно перехватываешь и "глушишь" (запихиваешь в ApexPages.Message). Для страницы это ок, но когда тесты работают ты можешь получить такую вот ситуацию, когда вроде должно работать, а не работает и тишина.

Dmitry Shnyrev
Так сложно сказать что у тебя не работает.

Попробуй во первых убрать
try

catch (Exception e){...}

Возможно в тесте у тебя какой-то exception выпадает, а ты его успешно перехватываешь и "глушишь" (запихиваешь в ApexPages.Message). Для страницы это ок, но когда тесты работают ты можешь получить такую вот ситуацию, когда вроде должно работать, а не работает и тишина.


точно емае.

пр удалении System.DmlException: Delete failed. First exception on row 0 with id 0037F00000Sw6L7QAJ; first error: DELETE_FAILED, Your attempt to delete Asdfdnn kifdki could not be completed because it is associated with the following cases.: 00101052

на insert вот такая :

System.DmlException: Insert failed. First exception on row 0; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, Please enter Last Name: [Email]

что за фигня, я же вставляю как с visualforce все те же поля
Contact contact = new Contact(FirstName='dfgd', LastName='sfsjh', Email='dfd@sfgg.hu', Contact_Level__c='Primary', AccountId='0017F00000XQ8DxQAL');

cool
System.DmlException: Insert failed. First exception on row 0; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, Please enter Last Name: [Email]

У тебя случайно на Contact нет Custom Validation Rule?
Что-то мне не нравится вот это сообщение "Please enter Last Name: [Email]"

Dmitry Shnyrev
cool
System.DmlException: Insert failed. First exception on row 0; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, Please enter Last Name: [Email]

У тебя случайно на Contact нет Custom Validation Rule?
Что-то мне не нравится вот это сообщение "Please enter Last Name: [Email]"

проверил - точно нет

Зайди в developer console и просто запусти это

Contact contact = new Contact(FirstName='dfgd', LastName='sfsjh', Email='dfd@sfgg.hu', Contact_Level__c='Primary', AccountId='0017F00000XQ8DxQAL');

insert contact;

Если вылетит ошибка ищи что ты там намудрил в объекте Contact (или в триггере).

В нормальной ситуации тебе достаточно на контакте вообще заполнить одно поле Lastname и он уже будет сохраняться в базу. Если нет, значит ты добавил какие-то проверки про которые забыл или они работают неправильно.

Dmitry Shnyrev
Зайди в developer console и просто запусти это
Contact contact = new Contact(FirstName='dfgd', LastName='sfsjh', Email='dfd@sfgg.hu', Contact_Level__c='Primary', AccountId='0017F00000XQ8DxQAL');

insert contact;

Если вылетит ошибка ищи что ты там намудрил в объекте Contact (или в триггере).

success - прошло

Ну даже ХЗ.
В консоли создание контакта работает, а в тесте выдает ошибку?
Ищи в чем разница. Значит что-то не так заполняешь в тесте.

Делаю сейчас такое же. И проблема в том, что при наличии триггера метод не удаляет контакты, которые имеют Case!

Просто снеси все Cases с орга. Они тебе пока не нужны и только мешают. Это тестовые данные созданные вместе с оргом.

Dmitry Shnyrev
Просто снеси все Cases с орга. Они тебе пока не нужны и только мешают. Это тестовые данные созданные вместе с оргом.

Спасибо, попробую, но забегая на перед спрошу: Не возникнет ли такая же ситуация, если я создам новый контакт, которого Case создастся автоматически согласно триггера???

Вот триггер если что :

trigger ContactTrigger on Contact (after insert) {

list<Case> cases = new list<Case> ();
Set<Id> accIds = new Set<Id>();

for (Contact cont : Trigger.newMap.values()) {
accIds.add(cont.AccountId);
}
Map<Id,Account> mapIdToAcc = new Map<Id,Account>([SELECT Id,OwnerId FROM Account WHERE Id IN :accIds]);
for (Contact cont : Trigger.newMap.values()) {

if (cont.Contact_Level__c.contains('Primary')){

cases.add(new Case(ContactId=cont.Id, Status = 'Working', Origin = 'New Contact', Priority = 'High', OwnerId=mapIdToAcc.get(cont.AccountId).OwnerId));
}

if (cont.Contact_Level__c.contains('Secondary')){

cases.add(new Case(ContactId=cont.Id, Status = 'Working', Origin = 'New Contact', Priority = 'Medium', OwnerId=mapIdToAcc.get(cont.AccountId).OwnerId));
}

if (cont.Contact_Level__c.contains('Tertiary')){

cases.add(new Case(ContactId=cont.Id, Status = 'Working', Origin = 'New Contact', Priority = 'Low', OwnerId=mapIdToAcc.get(cont.AccountId).OwnerId));
}



}
insert cases;
}

pazik36
Спасибо, попробую, но забегая на перед спрошу: Не возникнет ли такая же ситуация, если я создам новый контакт, которого Case создастся автоматически согласно триггера???

Вообще такой вопрос я должен тебе задать
У тебя же код в руках, прочитай его

Это тоже самое что сказать:
"Я вот пишу письмо на английском, хотя читать даже по английски не умею"

Dmitry Shnyrev
pazik36
Спасибо, попробую, но забегая на перед спрошу: Не возникнет ли такая же ситуация, если я создам новый контакт, которого Case создастся автоматически согласно триггера???

Вообще такой вопрос я должен тебе задать
У тебя же код в руках, прочитай его :D

А что тут читать, я создам контакт, создастся case в зависимости от Contact Level, а потом я не смогу удалить этот контакт)

Хорошо, что мешает написать такой же триггер который удалит Case перед тем как удалить Contact?

Или

Закоментировать строчки с созданием Cases если они не нужны.

Dmitry Shnyrev
Хорошо, что мешает написать такой же триггер который удалит Case перед тем как удалить Contact?

Или

Закоментировать строчки с созданием Cases если они не нужны.

Закоментировать никак, а вот со вторым триггером наверное норм идея, если она не противоречит здравому смыслу!

А при чем здесь здравый смысл?
Задача есть?
Противоречит задаче?

Да нет. А не будет ли этот триггер мешать удалению контактов у которых нет Case?)))))) Ладно буду пробовать!

Как напишешь так триггер и будет работать. В программировании нет магии. Комп делает только то что от него просят.

Странно. Сделал вот так, но все равно не удаляет!

trigger Contact_Case_Trigger on Contact (before delete) {


list<Id> cases = new list<Id> ();
for (contact c : trigger.new){
if(c.Id !=null ) {

cases.add(c.Id);
}

}

if(cases.size()>0){
list<Case> cas= [select id from case where id in :cases];
delete cas;
}
}

Разберись с контектом триггера (Trigger Context) и почувствуй разницу между
Trigger.new и Trigger.old

Да, и начни переменные нормально называть (со смыслом). Увидишь еще ошибки.

Dmitry Shnyrev
Разберись с контектом триггера (Trigger Context) и почувствуй разницу между
Trigger.new и Trigger.old

Опс!!!!!!!: new Возвращает список новых версий записей sObject. Этот список sObject доступен только в триггерах вставки, обновления и восстановления, и записи могут быть изменены только перед триггерами.

old Возвращает список старых версий записей sObject. Этот список sObject доступен только в триггерах обновления и удаления.

Принято!

ах если бы ты еще понимал как называть переменные, то наверное такой ошибки бы и не возникло

list<Case> cas= [select  id from case where id in :cases];

:cases у тебя, это ниразу не cases, это contacts

https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_triggers_order_of_execution.htm

Maxim Elets
ах если бы ты еще понимал как называть переменные, то наверное такой ошибки бы и не возникло
list<Case> cas= [select  id from case where id in :cases];

:cases у тебя, это ниразу не cases, это contacts

https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_triggers_order_of_execution.htm

Согласен!!!. Но нифига!

Dmitry Shnyrev
Ты еще не разобрался NullPointerException?
Брось все и разбирайся пока не начнешь с закрытыми глазами понимать в чем причина ошибки.

А где можно детально разобрать эту ошибку?

Есть очень надежный источник информации для всех программистов!!!
https://goo.gl/qyE2LL

Interesting information? Help us, post link to social media..