Skip to main content
Register now for TDX! Join the must-attend event to experience whatโ€™s next and learn how to build it.

Apex ํŠธ๋ฆฌ๊ฑฐ ์‹œ์ž‘ํ•˜๊ธฐ

ํ•™์Šต ๋ชฉํ‘œ

์ด ์œ ๋‹›์„ ์™„๋ฃŒํ•˜๋ฉด ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • Salesforce ๊ฐœ์ฒด์— ๋Œ€ํ•œ ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํŠธ๋ฆฌ๊ฑฐ ์ปจํ…์ŠคํŠธ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํŠธ๋ฆฌ๊ฑฐ์—์„œ ํด๋ž˜์Šค ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํŠธ๋ฆฌ๊ฑฐ์˜ sObject addError() ๋งค์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ €์žฅ ์ž‘์—…์„ ์ œํ•œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์ฐธ๊ณ 

์ฐธ๊ณ 

ํ•œ๊ตญ์–ด๋กœ ํ•™์Šตํ•˜์‹œ๊ฒ ์–ด์š”? Trailhead playground์—์„œ ํ•œ๊ตญ์–ด๋กœ ์‹ค์Šต ๊ณผ์ œ๋ฅผ ์‹œ์ž‘ํ•˜๊ณ , ๊ด„ํ˜ธ ์•ˆ์— ์ œ๊ณต๋œ ๋ฒˆ์—ญ์„ ์‚ฌ์šฉํ•ด ํƒ์ƒ‰ํ•ด ๋ณด์„ธ์š”. ์˜์–ด ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์‹ค์Šต ๊ณผ์ œ ๊ฒ€์ฆ์ด ์ด๋ฃจ์–ด์ง€๋ฏ€๋กœ ์˜๋ฌธ์œผ๋กœ ํ‘œ์‹œ๋œ ๊ฐ’๋งŒ ๋ณต์‚ฌํ•ด ๋ถ™์—ฌ ๋„ฃ์Šต๋‹ˆ๋‹ค. ํ•œ๊ตญ์–ด ์กฐ์ง์—์„œ ์‹ค์Šต ๊ณผ์ œ๋ฅผ ํ†ต๊ณผํ•˜์ง€ ๋ชปํ•œ ๊ฒฝ์šฐ, (1) ๋กœ์บ˜์„ ๋ฏธ๊ตญ์„ ๋ฐ”๊พธ๊ณ  (2) ์—ฌ๊ธฐ์— ์ œ์‹œ๋œ ์ง€์นจ์— ๋”ฐ๋ผ ์–ธ์–ด๋ฅผ ์˜์–ด๋กœ ๋ฐ”๊พผ ํ›„ (3) "Check Challenge(๊ณผ์ œ ํ™•์ธ)" ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ๋‹ค์‹œ ์ง„ํ–‰ํ•ด ๋ณด์„ธ์š”.

์›ํ•˜๋Š” ์–ธ์–ด๋กœ Trailhead ์‚ฌ์šฉํ•˜๊ธฐ ๋ฑƒ์ง€๋ฅผ ํ™•์ธํ•ด ํ˜„์ง€ํ™”๋œ Trailhead ๊ฒฝํ—˜์„ ํ™œ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด์„ธ์š”.

์‹œ์ž‘ํ•˜๊ธฐ ์ „์—

Apex ํŠธ๋ฆฌ๊ฑฐ๋Š” ์œ ์šฉํ•˜๊ณ  ์žฌ๋ฏธ์žˆ์œผ๋ฉฐ ํ›Œ๋ฅญํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ชจ๋“ˆ์„ ํ†ตํ•ด ์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์„ ์‹œ์ž‘ํ•  ์ˆ˜๋„ ์žˆ์œผ๋ฉฐ ๋‹ค๋ฅธ Salesforce ๊ธฐ๋Šฅ๋„ ์•Œ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— Apex ํŠธ๋ฆฌ๊ฑฐ์˜ ์„ฑ๋Šฅ์„ ํ™•์ธํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ชจ๋“ˆ์„ ์ตœ๋Œ€ํ•œ ํ™œ์šฉํ•˜๋ ค๋ฉด ๋จผ์ € ๋‹ค์Œ ๋ชจ๋“ˆ์„ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

Apex ํŠธ๋ฆฌ๊ฑฐ ์ž‘์„ฑํ•˜๊ธฐ

Apex ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์‚ฝ์ž…, ์—…๋ฐ์ดํŠธ ๋˜๋Š” ์‚ญ์ œ์™€ ๊ฐ™์€ Salesforce์˜ ๋ ˆ์ฝ”๋“œ์— ๋Œ€ํ•œ ์ด๋ฒคํŠธ ์ „ํ›„์— ๋งž์ถคํ˜• ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‹œ์Šคํ…œ์ด ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ์ง€์›ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ด Apex๋Š” ๋ ˆ์ฝ”๋“œ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ ํŠธ๋ฆฌ๊ฑฐ ์ง€์›์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŠน์ • ์กฐ๊ฑด์— ๋”ฐ๋ผ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ฑฐ๋‚˜ ๊ด€๋ จ ๋ ˆ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ํŠน์ • ์ž‘์—…์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ์ œํ•œํ•ฉ๋‹ˆ๋‹ค. ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ SOQL ๋ฐ DML ์‹คํ–‰ ๋˜๋Š” ๋งž์ถคํ˜• Apex ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์„ ํฌํ•จํ•˜์—ฌ Apex์—์„œ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Salesforce ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค์—์„œ ํฌ์ธํŠธ ์•ค ํด๋ฆญ ๋„๊ตฌ๋กœ ์ˆ˜ํ–‰ ๋ถˆ๊ฐ€๋Šฅํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ํ•„๋“œ ๊ฐ’์˜ ์œ ํšจ์„ฑ์„ ๊ฒ€์‚ฌํ•˜๊ฑฐ๋‚˜ ๋ ˆ์ฝ”๋“œ์˜ ํ•„๋“œ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฒฝ์šฐ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๊ทœ์น™๊ณผ ํ”Œ๋กœ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์„ฑ๋Šฅ๊ณผ ํ™•์žฅ์ด ์ค‘์š”ํ•˜๊ฑฐ๋‚˜, ํฌ์ธํŠธ ์•ค ํด๋ฆญ ๋„๊ตฌ์šฉ์œผ๋กœ๋Š” ๋…ผ๋ฆฌ๊ฐ€ ๋„ˆ๋ฌด ๋ณต์žกํ•˜๊ฑฐ๋‚˜, CPU์— ๋ถ€๋‹ด์„ ์ฃผ๋Š” ์ž‘์—…์„ ์‹คํ–‰ํ•  ๋•Œ๋Š” Apex ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๊ณ„์ • ๋˜๋Š” ์—ฐ๋ฝ์ฒ˜์™€ ๊ฐ™์€ ์ตœ์ƒ์œ„ ํ‘œ์ค€ ๊ฐœ์ฒด, ๋งž์ถคํ˜• ๊ฐ์ฒด ๋ฐ ์ผ๋ถ€ ํ‘œ์ค€ ํ•˜์œ„ ๊ฐœ์ฒด์— ๋Œ€ํ•ด ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŠธ๋ฆฌ๊ฑฐ๋Š” ์ƒ์„ฑ ์‹œ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ™œ์„ฑํ™”๋ฉ๋‹ˆ๋‹ค. Salesforce๋Š” ์ง€์ •๋œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•  ๋•Œ ์ž๋™์œผ๋กœ ํ™œ์„ฑ ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

ํŠธ๋ฆฌ๊ฑฐ ๊ตฌ๋ฌธ

ํŠธ๋ฆฌ๊ฑฐ ์ •์˜์˜ ๊ตฌ๋ฌธ์€ ํด๋ž˜์Šค ์ •์˜์˜ ๊ตฌ๋ฌธ๊ณผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ํŠธ๋ฆฌ๊ฑฐ ์ •์˜๋Š” trigger ํ‚ค์›Œ๋“œ๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ํŠธ๋ฆฌ๊ฑฐ ์ด๋ฆ„, ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ์—ฐ๊ฒฐ๋œ Salesforce ๊ฐœ์ฒด ๋ฐ ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ์‹คํ–‰๋˜๋Š” ์กฐ๊ฑด์ด ๋”ฐ๋ฆ…๋‹ˆ๋‹ค. ํŠธ๋ฆฌ๊ฑฐ์˜ ๊ตฌ๋ฌธ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

trigger TriggerName on ObjectName (trigger_events) {
   code_block
}

์‚ฝ์ž…, ์—…๋ฐ์ดํŠธ, ์‚ญ์ œ ๋ฐ ์‚ญ์ œ ์ทจ์†Œ ์ž‘์—… ์ „ํ›„์— ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ์‹คํ–‰ํ•˜๋ ค๋ฉด ์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„๋œ ๋ชฉ๋ก์— ์—ฌ๋Ÿฌ ํŠธ๋ฆฌ๊ฑฐ ์ด๋ฒคํŠธ๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋Š” ์ด๋ฒคํŠธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • before insert(์‚ฝ์ž… ์ „)
  • before update(์—…๋ฐ์ดํŠธ ์ „)
  • before delete(์‚ญ์ œ ํ›„)
  • after insert(์‚ฝ์ž… ํ›„)
  • after update(์—…๋ฐ์ดํŠธ ํ›„)
  • after delete(์‚ญ์ œ ํ›„)
  • after undelete(์‚ญ์ œ ์ทจ์†Œ ํ›„)

ํŠธ๋ฆฌ๊ฑฐ ์˜ˆ์ œ

์ด ๊ฐ„๋‹จํ•œ ํŠธ๋ฆฌ๊ฑฐ๋Š” ๊ณ„์ •์„ ์‚ฝ์ž…ํ•˜๊ณ  ๋””๋ฒ„๊ทธ ๋กœ๊ทธ์— ๋ฉ”์‹œ์ง€๋ฅผ ์“ฐ๊ธฐ ์ „์— ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

  1. Developer Console์—์„œ File(ํŒŒ์ผ) | New(์ƒˆ๋กœ ๋งŒ๋“ค๊ธฐ) | Apex Trigger(Apex ํŠธ๋ฆฌ๊ฑฐ)๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
  2. ํŠธ๋ฆฌ๊ฑฐ ์ด๋ฆ„์— HelloWorldTrigger๋ฅผ ์ž…๋ ฅํ•œ ๋‹ค์Œ sObject์— ๋Œ€ํ•œ Account(๊ณ„์ •)๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค. Submit(์ œ์ถœ)์„ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
  3. ๊ธฐ๋ณธ ์ฝ”๋“œ๋ฅผ ๋‹ค์Œ์œผ๋กœ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค.
trigger HelloWorldTrigger on Account (before insert) {
	System.debug('Hello World!');
}
  1. ์ €์žฅํ•˜๋ ค๋ฉด Ctrl+S๋ฅผ ๋ˆ„๋ฆ…๋‹ˆ๋‹ค.
  2. ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋ ค๋ฉด ๊ณ„์ •์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
    • Debug(๋””๋ฒ„๊ทธ) | Open Execute Anonymous Window(์ต๋ช… ์‹คํ–‰ ์ฐฝ ์—ด๊ธฐ)๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
    • ์ƒˆ ์ฐฝ์—์„œ ๋‹ค์Œ์„ ์ถ”๊ฐ€ํ•œ ๋‹ค์Œ Execute(์‹คํ–‰)๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
Account a = new Account(Name='Test Trigger');
insert a;
  1. ๋””๋ฒ„๊ทธ ๋กœ๊ทธ์—์„œ Hello World! ๊ตฌ๋ฌธ์„ ์ฐพ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ๋กœ๊ทธ๋Š” ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ์‹คํ–‰๋˜์—ˆ์Œ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

ํŠธ๋ฆฌ๊ฑฐ ์œ ํ˜•

ํŠธ๋ฆฌ๊ฑฐ์—๋Š” ๋‘ ๊ฐ€์ง€ ์œ ํ˜•์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • Before triggers - ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅํ•˜๊ธฐ ์ „์— ๋ ˆ์ฝ”๋“œ ๊ฐ’์„ ์—…๋ฐ์ดํŠธํ•˜๊ฑฐ๋‚˜ ์œ ํšจ์„ฑ์„ ๊ฒ€์‚ฌํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • After triggers - ์‹œ์Šคํ…œ์—์„œ ์„ค์ •ํ•œ ํ•„๋“œ ๊ฐ’(์˜ˆ: ๋ ˆ์ฝ”๋“œ์˜ Id ๋˜๋Š” LastModifiedDate ํ•„๋“œ)์— ์•ก์„ธ์Šค ๋ฐ ๋‹ค๋ฅธ ๋ ˆ์ฝ”๋“œ์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. after trigger๊ฐ€ ๋ฐœ์ƒํ•œ ๋ ˆ์ฝ”๋“œ๋Š” ์ฝ๊ธฐ ์ „์šฉ์ž…๋‹ˆ๋‹ค.

์ปจํ…์ŠคํŠธ ๋ณ€์ˆ˜ ์‚ฌ์šฉ

ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ๋ฐœ์ƒํ•œ ๋ ˆ์ฝ”๋“œ์— ์•ก์„ธ์Šคํ•˜๋ ค๋ฉด ์ปจํ…์ŠคํŠธ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด Trigger.new์—๋Š” ํŠธ๋ฆฌ๊ฑฐ ์‚ฝ์ž… ๋˜๋Š” ์—…๋ฐ์ดํŠธ์— ์‚ฝ์ž…๋œ ๋ชจ๋“  ๋ ˆ์ฝ”๋“œ๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. Trigger.old์—์„œ ํŠธ๋ฆฌ๊ฑฐ ์—…๋ฐ์ดํŠธ์— ์—…๋ฐ์ดํŠธ๋˜๊ธฐ ์ „์˜ sObject ์ด์ „ ๋ฒ„์ „ ๋˜๋Š” ํŠธ๋ฆฌ๊ฑฐ ์‚ญ์ œ์—์„œ ์‚ญ์ œ๋œ sObject ๋ชฉ๋ก์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ํ•˜๋‚˜์˜ ๋ ˆ์ฝ”๋“œ๊ฐ€ ์‚ฝ์ž…๋˜๊ฑฐ๋‚˜ API ๋˜๋Š” Apex๋ฅผ ํ†ตํ•ด ๋งŽ์€ ๋ ˆ์ฝ”๋“œ๊ฐ€ ๋Œ€๋Ÿ‰์œผ๋กœ ์‚ฝ์ž…๋  ๊ฒฝ์šฐ ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ Trigger.new์™€ ๊ฐ™์€ ์ปจํ…์ŠคํŠธ ๋ณ€์ˆ˜์— ํ•˜๋‚˜์˜ ๋ ˆ์ฝ”๋“œ๋งŒ ๋˜๋Š” ์—ฌ๋Ÿฌ ๋ ˆ์ฝ”๋“œ๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Trigger.new๋ฅผ ๋ฐ˜๋ณตํ•˜์—ฌ ๊ฐ ๊ฐœ๋ณ„ sObject๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ์˜ˆ์ œ๋Š” HelloWorldTrigger ์˜ˆ์‹œ ํŠธ๋ฆฌ๊ฑฐ์˜ ์ˆ˜์ •๋œ ๋ฒ„์ „์ž…๋‹ˆ๋‹ค. for ๋ฃจํ”„์—์„œ ๊ฐ ๊ณ„์ •์„ ๋ฐ˜๋ณตํ•˜๊ณ  ๊ฐ๊ฐ์— ๋Œ€ํ•œ Description(์„ค๋ช…) ํ•„๋“œ๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.

trigger HelloWorldTrigger on Account (before insert) {
    for(Account a : Trigger.new) {
        a.Description = 'New description';
    }
}
Note

์‹œ์Šคํ…œ์€ ํŠธ๋ฆฌ๊ฑฐ ์‹คํ–‰์ด ์™„๋ฃŒ๋œ ํ›„ ์ด์ „ ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ์‹คํ–‰ํ•œ ๋ ˆ์ฝ”๋“œ๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. DML ์‚ฝ์ž… ๋˜๋Š” ์—…๋ฐ์ดํŠธ ์ž‘์—…์„ ๋ช…์‹œ์ ์œผ๋กœ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ณ  ํŠธ๋ฆฌ๊ฑฐ์˜ ๋ ˆ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น ๋ ˆ์ฝ”๋“œ์— ๋Œ€ํ•ด DML ๋ฌธ์„ ์ˆ˜ํ–‰ํ•˜๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์ผ๋ถ€ ๋‹ค๋ฅธ ์ปจํ…์ŠคํŠธ ๋ณ€์ˆ˜๋Š” ์—…๋ฐ์ดํŠธ ๋˜๋Š” ๊ธฐํƒ€ ์ด๋ฒคํŠธ๋กœ ์ธํ•ด ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ์‹คํ–‰๋˜์—ˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๋ถ€์šธ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ณ€์ˆ˜๋Š” ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ์—ฌ๋Ÿฌ ์ด๋ฒคํŠธ๋ฅผ ๊ฒฐํ•ฉํ•  ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์˜ ์˜ˆ๋ฅผ ํ™•์ธํ•ด ๋ณด์„ธ์š”.

trigger ContextExampleTrigger on Account (before insert, after insert, after delete) {
    if (Trigger.isInsert) {
        if (Trigger.isBefore) {
            // Process before insert
        } else if (Trigger.isAfter) {
            // Process after insert
        }
    }
    else if (Trigger.isDelete) {
        // Process after delete
    }
}

๋‹ค์Œ ํ‘œ๋Š” ํŠธ๋ฆฌ๊ฑฐ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ์ปจํ…์ŠคํŠธ ๋ณ€์ˆ˜์˜ ํฌ๊ด„์ ์ธ ๋ชฉ๋ก์ž…๋‹ˆ๋‹ค.

๋ณ€์ˆ˜

์‚ฌ์šฉ

isExecuting

Apex ์ฝ”๋“œ์˜ ํ˜„์žฌ ์ปจํ…์ŠคํŠธ๊ฐ€ Visualforce ํŽ˜์ด์ง€, ์›น ์„œ๋น„์Šค ๋˜๋Š” executeanonymous() API ํ˜ธ์ถœ์ด ์•„๋‹Œ ํŠธ๋ฆฌ๊ฑฐ์ธ ๊ฒฝ์šฐ true๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

isInsert

Salesforce ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค, Apex ๋˜๋Š” API์—์„œ ์‚ฝ์ž… ์ž‘์—…์œผ๋กœ ์ธํ•ด ์ด ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ์‹คํ–‰๋œ ๊ฒฝ์šฐ true๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

isUpdate

Salesforce ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค, Apex ๋˜๋Š” API์—์„œ ์—…๋ฐ์ดํŠธ ์ž‘์—…์œผ๋กœ ์ธํ•ด ์ด ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ์‹คํ–‰๋œ ๊ฒฝ์šฐ true๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

isDelete

Salesforce ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค, Apex ๋˜๋Š” API์—์„œ ์‚ญ์ œ ์ž‘์—…์œผ๋กœ ์ธํ•ด ์ด ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ์‹คํ–‰๋œ ๊ฒฝ์šฐ true๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

isBefore

๋ ˆ์ฝ”๋“œ๊ฐ€ ์ €์žฅ๋˜๊ธฐ ์ „์— ์ด ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ์‹คํ–‰๋œ ๊ฒฝ์šฐ true๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

isAfter

๋ชจ๋“  ๋ ˆ์ฝ”๋“œ๊ฐ€ ์ €์žฅ๋œ ํ›„์— ์ด ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ์‹คํ–‰๋œ ๊ฒฝ์šฐ true๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

isUndelete

Recycle Bin(ํœด์ง€ํ†ต)์—์„œ ๋ ˆ์ฝ”๋“œ๋ฅผ ๋ณต๊ตฌํ•œ ํ›„ ์ด ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ์‹คํ–‰๋œ ๊ฒฝ์šฐ true๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ณต๊ตฌ๋Š” Salesforce ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค, Apex ๋˜๋Š” API์—์„œ ์‚ญ์ œ ์ทจ์†Œ ์ž‘์—… ํ›„์— ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

new

sObject ๋ ˆ์ฝ”๋“œ์˜ ์ƒˆ ๋ฒ„์ „ ๋ชฉ๋ก์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์ด sObject ๋ชฉ๋ก์€ insert, update ๋ฐ undelete ํŠธ๋ฆฌ๊ฑฐ์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋ ˆ์ฝ”๋“œ๋Š” before ํŠธ๋ฆฌ๊ฑฐ์—๋งŒ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

newMap

sObject ๋ ˆ์ฝ”๋“œ์˜ ์ƒˆ ๋ฒ„์ „์— ๋Œ€ํ•œ ID ์ง€๋„์ž…๋‹ˆ๋‹ค.

์ด ์ง€๋„๋Š” before update, after insert, after update ๋ฐ after undelete ํŠธ๋ฆฌ๊ฑฐ์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

old

sObject ๋ ˆ์ฝ”๋“œ์˜ ์ด์ „ ๋ฒ„์ „ ๋ชฉ๋ก์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์ด sObject ๋ชฉ๋ก์€ update and delete ํŠธ๋ฆฌ๊ฑฐ์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

oldMap

sObject ๋ ˆ์ฝ”๋“œ์˜ ์ด์ „ ๋ฒ„์ „์— ๋Œ€ํ•œ ID ์ง€๋„์ž…๋‹ˆ๋‹ค.

์ด ์ง€๋„๋Š” update ๋ฐ delete ํŠธ๋ฆฌ๊ฑฐ์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

operationType

ํ˜„์žฌ ์ž‘์—…์— ํ•ด๋‹นํ•˜๋Š” System.TriggerOperation ์œ ํ˜•์˜ ์—ด๊ฑฐํ˜•์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

System.TriggerOperation ์—ด๊ฑฐํ˜•์˜ ๊ฐ€๋Šฅํ•œ ๊ฐ’์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. BEFORE_INSERT, BEFORE_UPDATE, BEFORE_DELETE, AFTER_INSERT, AFTER_UPDATE, AFTER_DELETE, ๋ฐ AFTER_UNDELETE. ๋‹ค์–‘ํ•œ ํŠธ๋ฆฌ๊ฑฐ ์œ ํ˜•์— ๋”ฐ๋ผ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋…ผ๋ฆฌ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒฝ์šฐ ๊ณ ์œ ํ•œ ํŠธ๋ฆฌ๊ฑฐ ์‹คํ–‰ ์—ด๊ฑฐ ์ƒํƒœ์˜ ์ˆœ์—ด์ด ๋‹ค๋ฅธ switch ๋ฌธ์„ ์‚ฌ์šฉํ•ด ๋ณด์„ธ์š”.

size

ํŠธ๋ฆฌ๊ฑฐ ํ˜ธ์ถœ์—์„œ ์ฒ˜๋ฆฌ๋˜๋Š” ๋ ˆ์ฝ”๋“œ ๊ฐœ์ˆ˜์ž…๋‹ˆ๋‹ค. 200๊ฐœ ์ดˆ๊ณผ์˜ ๋ ˆ์ฝ”๋“œ๋ฅผ ํฌํ•จํ•˜๋Š” DML ์ž‘์—…์€ ๋ฐฐ์น˜ ๋‹จ์œ„๋กœ ์ฒ˜๋ฆฌ๋˜๋ฉฐ, ํŠธ๋ฆฌ๊ฑฐ๋Š” ๊ฐ ๋ฐฐ์น˜์— ๋Œ€ํ•ด ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. Trigger.size๋Š” DML ์ž‘์—…์˜ ์ด ๋ ˆ์ฝ”๋“œ ๊ฐœ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ˜„์žฌ ๋ฐฐ์น˜์— ํฌํ•จ๋œ ๋ ˆ์ฝ”๋“œ์˜ ๊ฐœ์ˆ˜๋งŒ์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.

ํŠธ๋ฆฌ๊ฑฐ์—์„œ ํด๋ž˜์Šค ๋ฉ”์„œ๋“œ ํ˜ธ์ถœํ•˜๊ธฐ

ํŠธ๋ฆฌ๊ฑฐ์—์„œ ๊ณต์šฉ ์œ ํ‹ธ๋ฆฌํ‹ฐ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํด๋ž˜์Šค์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๊ณ  ํŠธ๋ฆฌ๊ฑฐ ํฌ๊ธฐ๊ฐ€ ์ค„์–ด๋“ค๋ฉฐ Apex ์ฝ”๋“œ์˜ ์œ ์ง€ ๊ด€๋ฆฌ๊ฐ€ ํ–ฅ์ƒ๋ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ๊ฐœ์ฒด ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ์˜ˆ์ œ ํŠธ๋ฆฌ๊ฑฐ๋Š” ํŠธ๋ฆฌ๊ฑฐ์—์„œ ์ •์  ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ์‚ฝ์ž… ์ด๋ฒคํŠธ๋กœ ์ธํ•ด ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ์‹คํ–‰๋œ ๊ฒฝ์šฐ ์˜ˆ์ œ์—์„œ CustomContactNotification ํด๋ž˜์Šค์— ๋Œ€ํ•œ ์ •์  notifyUsers() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ด ์œ ํ‹ธ๋ฆฌํ‹ฐ ๋ฉ”์„œ๋“œ๋Š” ํŠธ๋ฆฌ๊ฑฐ์— ์ •์˜๋œ Salesforce ์‚ฌ์šฉ์ž์—๊ฒŒ ์‚ฌ์šฉ์ž ์ •์˜ ์•Œ๋ฆผ์„ ์ „์†กํ•ฉ๋‹ˆ๋‹ค. ์•Œ๋ฆผ์—๋Š” ์‚ฝ์ž…๋œ ์—ฐ๋ฝ์ฒ˜ ๋ ˆ์ฝ”๋“œ์˜ ์ˆ˜๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

Note

์ด ์˜ˆ์ œ์˜ ๊ฒฝ์šฐ, ์‚ฌ์šฉ์ž ์ •์˜ ์•Œ๋ฆผ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์ •์˜ ์•Œ๋ฆผ์€ Lightning Experience์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•Œ๋ฆผ ์ƒ์„ฑ ๋ฐ ํŽธ์ง‘์„ ์œ„ํ•ด์„œ๋Š” ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ ์‚ฌ์šฉ์ž ์ •์˜ ์‚ฌ์šฉ์ž ๊ถŒํ•œ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋ฐ์Šคํฌํ†ฑ ๋˜๋Š” ๋ชจ๋ฐ”์ผ ์•Œ๋ฆผ ์ƒ์„ฑ์„ ์ฐธ์กฐํ•˜์„ธ์š”.

  1. ๋ฐ์Šคํฌํ†ฑ ์‚ฌ์šฉ์ž ์ •์˜ ์•Œ๋ฆผ ์ƒ์„ฑํ•˜๊ธฐ.
    • Setup(์„ค์ •)์—์„œ Quick Find(๋น ๋ฅธ ์ฐพ๊ธฐ) ์ƒ์ž์— Notification Builder(์•Œ๋ฆผ ๋นŒ๋”)๋ฅผ ์ž…๋ ฅํ•œ ํ›„ Custom Notifications(์‚ฌ์šฉ์ž ์ •์˜ ์•Œ๋ฆผ)๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.
    • New(์ƒˆ๋กœ ๋งŒ๋“ค๊ธฐ)๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
    • ์‚ฌ์šฉ์ž ์ •์˜ ์•Œ๋ฆผ ์ด๋ฆ„์— New Contact Notification(์ƒˆ ์—ฐ๋ฝ์ฒ˜ ์•Œ๋ฆผ)์„ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค.
    • API Name(API ์ด๋ฆ„)์— New_Contact_Notification์„ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค.
    • ์ง€์›๋˜๋Š” ์ฑ„๋„์—์„œ Desktop(๋ฐ์Šคํฌํ†ฑ)์„ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.
    • Save(์ €์žฅ)๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
  2. Developer Console์—์„œ File(ํŒŒ์ผ) | New(์ƒˆ๋กœ ๋งŒ๋“ค๊ธฐ) | Apex Class(Apex ํด๋ž˜์Šค)๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
  3. CustomContactNotification์„ ์ž…๋ ฅํ•˜๊ณ  OK(ํ™•์ธ)๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
  4. ๊ธฐ๋ณธ ํด๋ž˜์Šค ๋ณธ๋ฌธ์„ ์•„๋ž˜์— ์ œ์‹œ๋œ CustomContactNotification ํด๋ž˜์Šค ์˜ˆ์‹œ๋กœ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค.
public with sharing class CustomContactNotification {
    // Public method
    public static void notifyUsers(Set<String> recipientsIds, Integer recordCount) {
        

        // Get the ID for the custom notification type created in Setup
 		CustomNotificationType notificationType =
            [SELECT Id, DeveloperName
             FROM CustomNotificationType
             WHERE DeveloperName='New_Contact_Notification'];
        

        // Create a new custom notification
        Messaging.CustomNotification notification = new Messaging.CustomNotification();
        

        // Set the contents for the notification
        notification.setTitle('Trailhead Trigger Tutorial');
        notification.setBody(recordCount + ' contact(s) were inserted.');


        // Set the notification type and target
        notification.setNotificationTypeId(notificationType.Id);
        // '000000000000000AAA' is a dummy targetId value
        notification.setTargetId('000000000000000AAA');
        

       // Send the notification
       try {
           notification.send(recipientsIds);
           System.debug('Custom notification sent successfully.');
       }
       catch (Exception e) {
           System.debug('Problem sending notification: ' + e.getMessage());
        }
    }
}
  1. Developer Console์—์„œ File(ํŒŒ์ผ) | New(์ƒˆ๋กœ ๋งŒ๋“ค๊ธฐ) | Apex Trigger(Apex ํŠธ๋ฆฌ๊ฑฐ)๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
  2. ํŠธ๋ฆฌ๊ฑฐ ์ด๋ฆ„์— ContactNotificationTrigger๋ฅผ ์ž…๋ ฅํ•œ ๋‹ค์Œ sObject์— ๋Œ€ํ•œ Contact(์—ฐ๋ฝ์ฒ˜)๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค. Submit(์ œ์ถœ)์„ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
  3. ๊ธฐ๋ณธ ์ฝ”๋“œ๋ฅผ ๋‹ค์Œ์œผ๋กœ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค.
trigger ContactNotificationTrigger on Contact (after insert, after delete) {
    if (Trigger.isInsert) {
        Integer recordCount = Trigger.new.size();
        

        // Set the recipientIDs to the current user
        Set<String> recipientIDs = new Set<String>{UserInfo.getUserId()};
      

        // Call a utility method from another class
        CustomContactNotification.notifyUsers(recipientIDs, recordCount);
    }
    else if (Trigger.isDelete) {
        // Process after delete
    }
}
  1. ์ €์žฅํ•˜๋ ค๋ฉด Ctrl+S๋ฅผ ๋ˆ„๋ฆ…๋‹ˆ๋‹ค.
  2. ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋ ค๋ฉด ์—ฐ๋ฝ์ฒ˜๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
    • Debug(๋””๋ฒ„๊ทธ) | Open Execute Anonymous Window(์ต๋ช… ์‹คํ–‰ ์ฐฝ ์—ด๊ธฐ)๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
    • ์ƒˆ ์ฐฝ์—์„œ ๋‹ค์Œ์„ ์ถ”๊ฐ€ํ•œ ๋‹ค์Œ Execute(์‹คํ–‰)๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
Contact c = new Contact(LastName='Test Contact');
insert c;
  1. ๋””๋ฒ„๊ทธ ๋กœ๊ทธ์—์„œ ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ์‹คํ–‰๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ๋กœ๊ทธ ๋๋ถ€๋ถ„์—์„œ ์œ ํ‹ธ๋ฆฌํ‹ฐ ๋ฉ”์„œ๋“œ(DEBUG|Custom notification sent successfully.)๋กœ ์ž‘์„ฑ๋œ ๋””๋ฒ„๊ทธ ๋ฉ”์‹œ์ง€๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค.
  2. ์ด์ œ ์•Œ๋ฆผ์ด ์ˆ˜์‹ ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ์•Œ๋ฆผ ํŒจ๋„์„ ์—ด๋ ค๋ฉด ์•Œ๋ฆผ ๋ฒจ๋ฅผ ํด๋ฆญํ•˜์„ธ์š”. ์ œ๋ชฉ์ด 'Trailhead Trigger Tutorial'์ด๊ณ  ๋ณธ๋ฌธ์ด '1 contact(s) were inserted(1๊ฐœ์˜ ์—ฐ๋ฝ์ฒ˜๊ฐ€ ์‚ฝ์ž…๋˜์—ˆ์Šต๋‹ˆ๋‹ค)'์ธ ์•Œ๋ฆผ์ด ํ‘œ์‹œ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ƒˆ ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ์žˆ์œผ๋ฉด ์—ฐ๋ฝ์ฒ˜๋ฅผ ํ•˜๋‚˜ ์ด์ƒ ์ถ”๊ฐ€ํ•  ๋•Œ๋งˆ๋‹ค ์‚ฌ์šฉ์ž ์ •์˜ ๋ฐ์Šคํฌํ†ฑ ์•Œ๋ฆผ์„ ๋ฐ›๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

ํŠธ๋ฆฌ๊ฑฐ๋Š” ์ข…์ข… ํŠธ๋ฆฌ๊ฑฐ ์ปจํ…์ŠคํŠธ์˜ ๋ ˆ์ฝ”๋“œ(์ด ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ ๋ ˆ์ฝ”๋“œ)์™€ ๊ด€๋ จ๋œ ๋ ˆ์ฝ”๋“œ์— ์•ก์„ธ์Šคํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

์ด ํŠธ๋ฆฌ๊ฑฐ๋Š” ๊ธฐํšŒ๊ฐ€ ์ด๋ฏธ ๊ณ„์ •๊ณผ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ง€ ์•Š์€ ๊ฒฝ์šฐ ์ƒˆ ๊ณ„์ • ๋˜๋Š” ์—…๋ฐ์ดํŠธ๋œ ๊ฐ ๊ณ„์ •์— ๋Œ€ํ•œ ๊ด€๋ จ ๊ธฐํšŒ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ํŠธ๋ฆฌ๊ฑฐ๋Š” ๋จผ์ € SOQL ์ฟผ๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜์—ฌ ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ์‹คํ–‰๋œ ๊ณ„์ •์— ๋Œ€ํ•œ ๋ชจ๋“  ํ•˜์œ„ ๊ธฐํšŒ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. ๋‹ค์Œ์œผ๋กœ ํŠธ๋ฆฌ๊ฑฐ๋Š” Trigger.new์˜ sObject ๋ชฉ๋ก์„ ๋ฐ˜๋ณตํ•˜์—ฌ ๊ฐ ๊ณ„์ • sObject๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. ๊ณ„์ •์— ๊ด€๋ จ๋œ ๊ธฐํšŒ sObject๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ for ๋ฃจํ”„๋Š” ๊ธฐํšŒ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ์ƒˆ๋กœ์šด ๊ธฐํšŒ๋ฅผ ์ƒ์„ฑํ•œ ๊ฒฝ์šฐ ์ตœ์ข… ๋ช…๋ น๋ฌธ์ด ์ด๋ฅผ ์‚ฝ์ž…ํ•ฉ๋‹ˆ๋‹ค.

  1. Developer Console์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์Œ ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค(HelloWorldTrigger ์˜ˆ์ œ์˜ ๋‹จ๊ณ„๋ฅผ ๋”ฐ๋ฅด์ง€๋งŒ ํŠธ๋ฆฌ๊ฑฐ ์ด๋ฆ„์— ๋Œ€ํ•ด AddRelatedRecord๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค).

trigger AddRelatedRecord on Account(after insert, after update) {
    List<Opportunity> oppList = new List<Opportunity>();
    // Get the related opportunities for the accounts in this trigger
    Map<Id,Account> acctsWithOpps = new Map<Id,Account>(
        [SELECT Id,(SELECT Id FROM Opportunities) FROM Account WHERE Id IN :Trigger.new]);
    // Add an opportunity for each account if it doesn't already have one.
    // Iterate through each account.
    for(Account a : Trigger.new) {
        System.debug('acctsWithOpps.get(a.Id).Opportunities.size()=' + acctsWithOpps.get(a.Id).Opportunities.size());
        // Check if the account already has a related opportunity.
        if (acctsWithOpps.get(a.Id).Opportunities.size() == 0) {
            // If it doesn't, add a default opportunity
            oppList.add(new Opportunity(Name=a.Name + ' Opportunity',
                                       StageName='Prospecting',
                                       CloseDate=System.today().addMonths(1),
                                       AccountId=a.Id));
        }
    }
    if (oppList.size() > 0) {
        insert oppList;
    }
}
  1. ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋ ค๋ฉด Salesforce ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค์—์„œ ๊ณ„์ •์„ ๋งŒ๋“ค๊ณ  Apples &amp; Oranges(์‚ฌ๊ณผ ๋ฐ ์˜ค๋ Œ์ง€)๋กœ ์ด๋ฆ„์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
  2. ๊ณ„์ • ํŽ˜์ด์ง€์˜ ๊ธฐํšŒ ๊ด€๋ จ ๋ชฉ๋ก์—์„œ ์ƒˆ ๊ธฐํšŒ๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค. ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ์ด ๊ธฐํšŒ๋ฅผ ์ž๋™์œผ๋กœ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.
Note

์ถ”๊ฐ€ํ•œ ํŠธ๋ฆฌ๊ฑฐ๋Š” ํŠธ๋ฆฌ๊ฑฐ ์ปจํ…์ŠคํŠธ์˜ ์ผ๋ถ€์ธ ๋ชจ๋“  ๋ ˆ์ฝ”๋“œ, ์ฆ‰ Trigger.new๋ฅผ ๋ฐ˜๋ณตํ•˜๋Š” for ๋ฃจํ”„๋ฅผ ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด ํŠธ๋ฆฌ๊ฑฐ์˜ ๋ฃจํ”„๊ฐ€ ๋” ํšจ์œจ์ ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํŠธ๋ฆฌ๊ฑฐ ์ปจํ…์ŠคํŠธ์—์„œ ๋ชจ๋“  ๊ณ„์ •์— ์‹ค์ œ๋กœ ์•ก์„ธ์Šคํ•  ํ•„์š”๋Š” ์—†์ง€๋งŒ ํ•˜์œ„ ์ง‘ํ•ฉ, ์ฆ‰ ๊ธฐํšŒ๊ฐ€ ์—†๋Š” ๊ณ„์ •์—๋งŒ ์•ก์„ธ์Šคํ•  ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ ์œ ๋‹›์—์„œ๋Š” ์ด ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ๋ณด๋‹ค ํšจ์œจ์ ์œผ๋กœ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ๋Œ€๋Ÿ‰ ํŠธ๋ฆฌ๊ฑฐ ๋””์ž์ธ ํŒจํ„ด ์œ ๋‹›์—์„œ ๊ธฐํšŒ๊ฐ€ ์—†๋Š” ๊ณ„์ •๋งŒ ๊ฐ€์ ธ์˜ค๋„๋ก SOQL ์ฟผ๋ฆฌ๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ด…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ํ•ด๋‹น ๋ ˆ์ฝ”๋“œ์— ๋Œ€ํ•ด์„œ๋งŒ ๋ฐ˜๋ณตํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐฐ์›๋‹ˆ๋‹ค.

ํŠธ๋ฆฌ๊ฑฐ ์˜ˆ์™ธ ์‚ฌ์šฉํ•˜๊ธฐ

ํŠน์ • ์กฐ๊ฑด์ด ์ถฉ์กฑ๋˜๋ฉด ๋ ˆ์ฝ”๋“œ๊ฐ€ ์ €์žฅ๋˜์ง€ ์•Š๋„๋ก ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ด ํŠน์ • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—…์— ๋Œ€ํ•œ ์ œํ•œ์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ํŠธ๋ฆฌ๊ฑฐ์— ๋ ˆ์ฝ”๋“œ๊ฐ€ ์ €์žฅ๋˜์ง€ ์•Š๋„๋ก ํ•˜๋ ค๋ฉด ๋ฌธ์ œ๊ฐ€ ๋˜๋Š” sObject์— ๋Œ€ํ•œ addError() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. addError() ๋ฉ”์„œ๋“œ๋Š” ํŠธ๋ฆฌ๊ฑฐ ๋‚ด๋ถ€์—์„œ ์น˜๋ช…์ ์ธ ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋Š” ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค์— ํ‘œ์‹œ๋˜๊ณ  ๊ธฐ๋ก๋ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ ํŠธ๋ฆฌ๊ฑฐ๋Š” ๊ด€๋ จ ๊ธฐํšŒ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ๊ณ„์ •์ด ์‚ญ์ œ๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ณ„์ •์„ ์‚ญ์ œํ•˜๋ฉด ๋ชจ๋“  ๊ด€๋ จ ๋ ˆ์ฝ”๋“œ๊ฐ€ ๊ณ„๋‹จ์‹์œผ๋กœ ์‚ญ์ œ๋ฉ๋‹ˆ๋‹ค. ์ด ํŠธ๋ฆฌ๊ฑฐ๋Š” ๊ธฐํšŒ์˜ ๊ณ„๋‹จ์‹ ์‚ญ์ œ๋ฅผ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค. ์ด ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•ด ๋ณด์„ธ์š”. ์ด์ „ ์˜ˆ์ œ๋ฅผ ์‹คํ–‰ํ•œ ๊ฒฝ์šฐ ์กฐ์ง์— ๊ด€๋ จ ๊ธฐํšŒ๊ฐ€ ์žˆ๋Š” Apples & Oranges๋ผ๋Š” ๊ณ„์ •์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์˜ˆ์ œ์—์„œ ํ•ด๋‹น ์ƒ˜ํ”Œ ๊ณ„์ •์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

  1. Developer Console์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์Œ ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
trigger AccountDeletion on Account (before delete) {
    // Prevent the deletion of accounts if they have related opportunities.
    for (Account a : [SELECT Id FROM Account
                     WHERE Id IN (SELECT AccountId FROM Opportunity) AND
                     Id IN :Trigger.old]) {
        Trigger.oldMap.get(a.Id).addError(
            'Cannot delete account with related opportunities.');
    }
}
  1. Salesforce ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค์—์„œ Apples &amp; Oranges ๊ณ„์ • ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜์—ฌ Delete(์‚ญ์ œ)๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
  2. ํ™•์ธ ํŒ์—…์—์„œ Delete(์‚ญ์ œ)๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.

Cannot delete account with related opportunities(๊ด€๋ จ ๊ธฐํšŒ๊ฐ€ ์žˆ๋Š” ๊ณ„์ •์„ ์‚ญ์ œํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค) ์‚ฌ์šฉ์ž ์ •์˜ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋กœ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์˜ค๋ฅ˜๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค.

  1. AccountDeletion ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค. ์ด ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ํ™œ์„ฑ ์ƒํƒœ๋กœ ๋‘๋ฉด ๊ณผ์ œ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
    • Setup(์„ค์ •)์—์„œ Apex Triggers๋ฅผ ๊ฒ€์ƒ‰ํ•ฉ๋‹ˆ๋‹ค.
    • Apex Triggers(Apex ํŠธ๋ฆฌ๊ฑฐ) ํŽ˜์ด์ง€์—์„œ AccountDeletion ํŠธ๋ฆฌ๊ฑฐ ์˜†์— ์žˆ๋Š” Edit(ํŽธ์ง‘)์„ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
    • Is Active(ํ™œ์„ฑ)๋ฅผ ์„ ํƒ ํ•ด์ œํ•ฉ๋‹ˆ๋‹ค.
    • Save(์ €์žฅ)๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
Note

ํŠธ๋ฆฌ๊ฑฐ์—์„œ addError()๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๋Œ€๋Ÿ‰ DML์ด ๋ถ€๋ถ„์ ์œผ๋กœ ์„ฑ๊ณตํ•˜์—ฌ ํ˜ธ์ถœ๋œ ๊ฒฝ์šฐ๋ฅผ ์ œ์™ธํ•˜๊ณ  ์ „์ฒด ์ž‘์—… ์ง‘ํ•ฉ์ด ๋กค๋ฐฑ๋˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

  • Salesforce Platform API์˜ ๋Œ€๋Ÿ‰ DML ํ˜ธ์ถœ์ด ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ์ƒ์„ฑํ•œ ๊ฒฝ์šฐ ๋Ÿฐํƒ€์ž„ ์—”์ง„์ด ์ž˜๋ชป๋œ ๋ ˆ์ฝ”๋“œ๋ฅผ ๋”ฐ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ๋Ÿฐํƒ€์ž„ ์—”์ง„์€ ์˜ค๋ฅ˜๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š์€ ๋ ˆ์ฝ”๋“œ๋ฅผ ๋ถ€๋ถ„์ ์œผ๋กœ ์ €์žฅํ•ด ๋ด…๋‹ˆ๋‹ค.
  • Apex์˜ DML ๋ฌธ์ด ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ์ƒ์„ฑํ•œ ๊ฒฝ์šฐ ๋ชจ๋“  ์˜ค๋ฅ˜๊ฐ€ ์ „์ฒด ์ž‘์—…์„ ๋กค๋ฐฑํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋Ÿฐํƒ€์ž„ ์—”์ง„์€ ์—ฌ์ „ํžˆ ์ž‘์—…์˜ ๋ชจ๋“  ๋ ˆ์ฝ”๋“œ๋ฅผ ์ฒ˜๋ฆฌํ•˜์—ฌ ํฌ๊ด„์ ์ธ ์˜ค๋ฅ˜ ๋ชฉ๋ก์„ ์ปดํŒŒ์ผํ•ฉ๋‹ˆ๋‹ค.

ํŠธ๋ฆฌ๊ฑฐ ๋ฐ ์ฝœ์•„์›ƒ

Apex๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์™ธ๋ถ€ ์›น ์„œ๋น„์Šค๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  Apex ์ฝ”๋“œ๋ฅผ ์™ธ๋ถ€ ์›น ์„œ๋น„์Šค์™€ ํ†ตํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์™ธ๋ถ€ ์›น ์„œ๋น„์Šค์— ๋Œ€ํ•œ Apex ํ˜ธ์ถœ์„ ์ฝœ์•„์›ƒ์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ฃผ์‹ ์‹œ์„ธ ์„œ๋น„์Šค์— ์ฝœ์•„์›ƒ์„ ๋งŒ๋“ค์–ด ์ตœ์‹  ์‹œ์„ธ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŠธ๋ฆฌ๊ฑฐ์—์„œ ํ˜ธ์ถœํ•  ๊ฒฝ์šฐ ํ˜ธ์ถœ์€ ํŠธ๋ฆฌ๊ฑฐ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์™ธ๋ถ€ ์„œ๋น„์Šค์˜ ์‘๋‹ต์„ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋™์•ˆ ์ž‘์—…์„ ์ฐจ๋‹จํ•˜์ง€ ์•Š๋„๋ก ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ˆ˜ํ–‰๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋น„๋™๊ธฐ ํ˜ธ์ถœ์€ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ํ”„๋กœ์„ธ์Šค์—์„œ ์ˆ˜ํ–‰๋˜๋ฉฐ ์™ธ๋ถ€ ์„œ๋น„์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•  ๊ฒฝ์šฐ ์‘๋‹ต์ด ์ˆ˜์‹ ๋ฉ๋‹ˆ๋‹ค.

ํŠธ๋ฆฌ๊ฑฐ์—์„œ ์ฝœ์•„์›ƒ์„ ๋งŒ๋“ค๋ ค๋ฉด ๋น„๋™๊ธฐ์ ์œผ๋กœ ์‹คํ–‰๋˜๋Š” ํด๋ž˜์Šค ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฉ”์„œ๋“œ๋ฅผ future ๋ฉ”์„œ๋“œ๋ผ๊ณ  ํ•˜๋ฉฐ @future(callout=true) ์ฃผ์„์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์ด ์˜ˆ์ œ ํด๋ž˜์Šค์—๋Š” ์ฝœ์•„์›ƒ์„ ๋งŒ๋“œ๋Š” future ๋ฉ”์„œ๋“œ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

Note

์ด ์˜ˆ์ œ์—์„œ๋Š” ์„ค๋ช… ๋ชฉ์ ์œผ๋กœ๋งŒ ๊ฐ€์ƒ์˜ ์—”๋“œํฌ์ธํŠธ URL์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋์ ์„ ์œ ํšจํ•œ URL๋กœ ๋ณ€๊ฒฝํ•˜๊ณ  ์—”๋“œํฌ์ธํŠธ์— ๋Œ€ํ•ด Salesforce์— ์›๊ฒฉ ์‚ฌ์ดํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์œผ๋ฉด ์ด ์˜ˆ์ œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

public class CalloutClass {
    @future(callout=true)
    public static void makeCallout() {
        HttpRequest request = new HttpRequest();
        // Set the endpoint URL.
        String endpoint = 'http://yourHost/yourService';
        request.setEndPoint(endpoint);
        // Set the HTTP verb to GET.
        request.setMethod('GET');
        // Send the HTTP request and get the response.
        HttpResponse response = new HTTP().send(request);
    }
}

์ด ์˜ˆ์ œ๋Š” ์ฝœ์•„์›ƒ์„ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ํด๋ž˜์Šค์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

trigger CalloutTrigger on Account (before insert, before update) {
    CalloutClass.makeCallout();
}

์ด ์„น์…˜์—์„œ๋Š” ์ฝœ์•„์›ƒ์˜ ๊ฐœ์š”๋งŒ ์ œ๊ณตํ•˜๋ฉฐ ์ฝœ์•„์›ƒ์„ ์ž์„ธํžˆ ๋‹ค๋ฃจ์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ Apex ๊ฐœ๋ฐœ์ž ๊ฐ€์ด๋“œ์˜ Apex๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฝœ์•„์›ƒ ํ˜ธ์ถœ์„ ์ฐธ์กฐํ•˜์„ธ์š”.

๋ฆฌ์†Œ์Šค

Salesforce ๋„์›€๋ง์—์„œ Trailhead ํ”ผ๋“œ๋ฐฑ์„ ๊ณต์œ ํ•˜์„ธ์š”.

Trailhead์— ๊ด€ํ•œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์˜๊ฒฌ์— ๊ท€ ๊ธฐ์šธ์ด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด์ œ Salesforce ๋„์›€๋ง ์‚ฌ์ดํŠธ์—์„œ ์–ธ์ œ๋“ ์ง€ ์ƒˆ๋กœ์šด ํ”ผ๋“œ๋ฐฑ ์–‘์‹์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ž์„ธํžˆ ์•Œ์•„๋ณด๊ธฐ ์˜๊ฒฌ ๊ณต์œ ํ•˜๊ธฐ