function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Devendra@SFDCDevendra@SFDC 

Avoid Duplicates in Master-Detail Relationship

 

 

Hi,

 

I have two custom object Job and Task.
They are having master detail relationship where Job(Master) --> Task(Child)

Each Job must contain multiple Tasks.

For e.g. Job Name: Prining Books

 

Task
        Task Name: Task 1
        Task Name : Task 2
       
It should not allow another record with student name as 'Task 1', because it is already available under Job.

But Task Name "Task 1" can be allowed to add under different Job (say under Job Design Graphics), simply because here Task 1 is belongs to different Job.

How to resolve this problem?

Thanks,
Devendra S    

Best Answer chosen by Admin (Salesforce Developers) 
tes2tes2

try this,  i did not test it but it should work in most case.  if you are try to switch names in a single batch you may have some issues,  you may need to do this in two steps or put in more logic.

 

EX.  A=C

B=A in single batch will faill since A has yet to commit.

 

 

 

trigger dup on Task__c (before insert,before update) {


Set<Id> stTemp=new Set<Id>();
for(Task__c st:Trigger.New)  
        stTemp.add(st.Job__c);
 
 
MAP<string,Task__c>  inDb = new MAP<string,Task__c>(); 
MAP<string,Task__c> inBatch = new MAP<string,Task__c>();
    for(Task__c st:Trigger.New)
    {   
        stTemp.add(st.Job__c);
    }
for ( Task__c t : [Select Id,Name,Job__c from Task__c where Job__c IN : stTemp])
    inDb.put(t.Name+t.Job__c,t);
   
 for ( Task__c t : Trigger.New) {
 
    if (inDb.containsKey(t.Name+t.Job__c)) {
    	if(Trigger.isInsert || t.id!=inDb.get(t.Name+t.Job__c).Id) //if update then ignore itself as a dup
            t.AddError('Task Name already Exists For this Job');
   }
   else if (inBatch.containsKey(t.Name+t.Job__c))
     {
        t.AddError('Duplicate in batch....');
        inBatch.get(t.Name+t.Job__c).AddError('Dup in Batch'); //optional, allow one or fail all
    }
    else {
        inBatch.put(t.Name+t.Job__c,t);
    }
  }
}

 

All Answers

tes2tes2

Create a trigger to check all the sibliing names on insert/update   a native alternative would be to create a new unique( External Id) field,  and create workflow to populate with Job__c.id+Task__c.Name

Andy BoettcherAndy Boettcher

I would agree with the previous poster.

 

You'll create a short "before insert, before update" Trigger on the "Task" object to query all other Task objects in the scope of the parent record, check the field for duplicates and return a "record.addError('You can't have duplicate Tasks on a Job!'); message.

 

-Andy

Devendra@SFDCDevendra@SFDC

 

Hi techman97,

 

I put the below the trigger, it works when i enter Task data from User Interface. But when i import data through Import Custom Wizard, it fails and duplicate Task records are entered. 

 

trigger avoidDuplicates on Task__c(before insert)
{
    Set<Id> stTemp=new Set<Id>();
    Map<String,Id> mp=new Map<String,Id>();
    for(Task__c st:Trigger.New)
    {   
        stTemp.add(st.Job__c);
    }

    List<Task__c> lstST=[Select Id,Name,Job__c from Task__c where Job__c IN : stTemp];

    for(Task__c st1:lstST)
    {
        mp.put(st1.Name,st1.Job__c);      
    }

    for(Task__c st1:Trigger.New)
    {
        if(mp.containsKey(st1.Name))
        {
            st1.addError('@@Duplicate Task is found for this Job@@');
        }
    }
}

 

I am looking for an trigger that will work for bulk records too. What changes are required in above code, so that it will work for bulk records too.

 

Thanks,

Devendra S

Andy BoettcherAndy Boettcher

That would be the expected behavior - you're only checking records that currently exist in the system.  Going through the import wizard is going to load a bunch of Tasks in the trigger.new list and your code isn't set to check that.

 

Look into the Trigger.newMap functionality and add that into your logic.

tes2tes2

You need to include your batch to the collection of siblings to test for matches.  

 

Ex...

SET<string> inDb = new SET<string>();
for ( task__c t : [Select Id,Name,Job__c from Task__c where Job__c IN : stTemp])
	inDb.add(t.Name+t.Job__c);

MAP<string,task__c> inBatch = new MAP<string,task__c>;
for ( task__c t : Trigger.New) {
	if (inDb.contains(t.Name+t.Job__c))
 		t.AddError('Task Name already Exists For this Job');
	else if (inBatch.containsKey(t.Name+t.Job__c)) {
		t.AddError('Duplicate in batch....');
 		inBatch.get(t.Name+t.Job__c).AddError('Dup in Batch'); //optional, allow one or fail all
	}
	else {
		inBatch.put(t.Name+t.Job__c,t);
	}
}

 

 

Devendra@SFDCDevendra@SFDC

 

Hi tes2,

 

The solution which you have given works with single record. But it does not work when i upload bulk data through import custom wizard.:(

 

Thanks,

Devendra

 


tes2tes2

Please post your code,  the code i provided checks both the batch and the data commited to the database.

Devendra@SFDCDevendra@SFDC

 

Hi tes2,

 

Sorry mate. My mistake. The code you have given is perfect. Thank you very much..!!

 

The below code is working well. Hope this will work at the time of update too. Not tested for update operation though. Will it work update also??

 

trigger dup on Task__c (before insert,before update) {

SET<string> inDb = new SET<string>();
Set<Id> stTemp=new Set<Id>();
 
MAP<string,Task__c> inBatch = new MAP<string,Task__c>();
    for(Task__c st:Trigger.New)
    {   
        stTemp.add(st.Job__c);
    }
for ( Task__c t : [Select Id,Name,Job__c from Task__c where Job__c IN : stTemp])
    inDb.add(t.Name+t.Job__c);
   
 for ( Task__c t : Trigger.New) {
    if (inDb.contains(t.Name+t.Job__c))
    
        t.AddError('Task Name already Exists For this Job');
   else if (inBatch.containsKey(t.Name+t.Job__c))
     {
        t.AddError('Duplicate in batch....');
        inBatch.get(t.Name+t.Job__c).AddError('Dup in Batch'); //optional, allow one or fail all
    }
    else {
        inBatch.put(t.Name+t.Job__c,t);
    }
  }
}

 

Thanks & Regards,

Devendra

Devendra@SFDCDevendra@SFDC

 

Hi tes2,

 

Can you please tell me, What changes are required for update? and It should apply for bulk records also.

 

Its urgent..:(

 

Thanks,

Devendra

tes2tes2

Sorry I didnt get this to you the first time, and I dont have the time code now here is a summary:

 

1.  create the inDB to a map<uniquestring,old task__c> instead of a set.

 

2.   when loop through the trigger.new ... in the inDB match logic is check to see if the Trigger.IsUpdate and additionally check to see if the id of the match is the same as the Task__c in the map done in 1 above.

Devendra@SFDCDevendra@SFDC

 

Hi tes2,

 

This is what i have tried today. Thank you so much.

 

 

trigger dup on Task__c (before insert,before update) {

if(Trigger.isBefore && Trigger.isInsert)
{
SET<string> inDb = new SET<string>();
 	Set<Id> stTemp=new Set<Id>();
 
MAP<string,Task__c> inBatch = new MAP<string,Task__c>();
for(Task__c st:Trigger.New)
    	{   
        stTemp.add(st.Job__c);
    	}
for ( Task__c t : [Select Id,Name,Job__c from Task__c where Job__c IN : stTemp])
    inDb.add(t.Name+t.Job__c);
   //inBatch.put(t.Name+t.Job__c,t);
       
for ( Task__c t : Trigger.New) {
    if (inDb.contains(t.Name+t.Job__c))
    
        t.AddError('Task Name already Exists For this Template');
        else if (inBatch.containsKey(t.Name+t.Job__c))
     	{
        t.AddError('Duplicate in batch....');
     //   inBatch.get(t.Name+t.Job__c).AddError('Dup in Batch'); 
    	}
else {
        inBatch.put(t.Name+t.Job__c,t);
    	}
    }
}

if(Trigger.isBefore && Trigger.isUpdate)
{
    String strTask1,strTask2;
    Set<Id> stTemp=new Set<Id>();
    
    for(Task__c st:Trigger.New)
    {
        Task__c oldTask=Trigger.oldMap.get(st.id);
        strTask1=oldTask.Name;
        strTask2=st.Name;
        stTemp.add(st.Job__c);
    }
    if(strTask1!=strTask2)
    {
        Map<String,Task__c> inDB=new Map<String,Task__c>();
        for(Task__c t:[Select Id,Name,Job__c from Task__c where Job__c In:stTemp])
        inDB.put(t.Name+t.Job__c,t);

        for(Task__c s:Trigger.New)
    {
        if(inDB.containsKey(s.Name+s.Job__c))
        {
             s.AddError('Task Name already Exists For this Template@@@@');
        }
    }
    }
        
  }
}

 

tes2tes2

try this,  i did not test it but it should work in most case.  if you are try to switch names in a single batch you may have some issues,  you may need to do this in two steps or put in more logic.

 

EX.  A=C

B=A in single batch will faill since A has yet to commit.

 

 

 

trigger dup on Task__c (before insert,before update) {


Set<Id> stTemp=new Set<Id>();
for(Task__c st:Trigger.New)  
        stTemp.add(st.Job__c);
 
 
MAP<string,Task__c>  inDb = new MAP<string,Task__c>(); 
MAP<string,Task__c> inBatch = new MAP<string,Task__c>();
    for(Task__c st:Trigger.New)
    {   
        stTemp.add(st.Job__c);
    }
for ( Task__c t : [Select Id,Name,Job__c from Task__c where Job__c IN : stTemp])
    inDb.put(t.Name+t.Job__c,t);
   
 for ( Task__c t : Trigger.New) {
 
    if (inDb.containsKey(t.Name+t.Job__c)) {
    	if(Trigger.isInsert || t.id!=inDb.get(t.Name+t.Job__c).Id) //if update then ignore itself as a dup
            t.AddError('Task Name already Exists For this Job');
   }
   else if (inBatch.containsKey(t.Name+t.Job__c))
     {
        t.AddError('Duplicate in batch....');
        inBatch.get(t.Name+t.Job__c).AddError('Dup in Batch'); //optional, allow one or fail all
    }
    else {
        inBatch.put(t.Name+t.Job__c,t);
    }
  }
}

 

This was selected as the best answer
sunu jsunu j
How did you write test class for this trigger?  Please help.
GhulamGhulam
Hi Tes2,
i have a problem .. help me..
Avoid Duplicate Name Only on master in Master-Detail relationship
Hi,
I have two custom object Claim__c(master) and Labour_Cost__c(detail).
They have master detail relationship.
I want to create a Trigger which prevent duplicate Name(standard field which is created default when we create any custom object) only on master object.
but we can multipe record with same Name from detail object and we select it from lookup field (Claim_Name__c) on detail object.
plz write a trigger for same.
for example: I have a record on Master Object with Name='S1 Claim' .
if i create a new record with Name 'S1 Claim' then it will display an error 'record already exists with same name'.
But,I can create multiple record with Name 'S1 Claim' from detail object.

Thanks,
Ghulam