In salesforce, how to create two sync Objects having similar fields - apex

How to Create two Objects say Obj1 and Obj2 having similar fields. On creating record of Obj1, associated Obj2 record should be created and vice versa. Additionally, updates should also be in sync i.e. updating the Obj1 should reflect in the Obj2 and vice versa.

Create both objects obj1 and obj2 with similar fields.
Now create Apex trigger on both objects with after insert and after update event as shown below.
trigger Obj1Trigger on obj1__c (after insert, after update) {
list<obj2__c> recList = new list<obj2__c>();
if(trigger.isAfter){
if(trigger.isInsert || trigger.isUpdate){
for(obj1__c ob : Trigger.new){
obj2__c obj2Rec = new obj2__c();
obj2Rec.name = ob.name;
obj2Rec.field1 = ob.field1;
obj2Rec.field2 = ob.field2;
obj2Rec.field3 = ob.field3;
recList.add(obj2Rec);
}
}
}
}
Similarly create trigger for obj2.
You will also need a way to associate two object's records with each other.
There are two ways to associate the related records.
way1:
identify two related records based on name field.
for this you will need to keep the name field unique(no records in the object have same name).
way2:
make one obj1 as parent and obj2 as child using master Detail relation ship field.

Related

Trigger to prevent User From Adding more than one product to an opportunity

So i have written a trigger to prevent user from entering more than one opportunity product to the same opportunity, but the problem is when he adds more than one opportunity product at the same time, my trigger does not fire, salesforce takes it as one product.
What can i add to my trigger to fix this ?
My trigger :
trigger OpportunityLineItemBeforeInsert on OpportunityLineItem (before insert) {
Set<Id>opportunityIds = new Set<Id>();
// get all parent IDs
for(OpportunityLineItem i : trigger.new)
{
opportunityIds.add(i.OpportunityId);
}
// query for related Olis (Opportunity Line Items)
Map<Id, Opportunity> opps = new Map<Id, Opportunity>([SELECT ID,
(SELECT ID
FROM OpportunityLineItems)
FROM Opportunity
WHERE ID IN :opportunityIds]);
for(OpportunityLineItem i : trigger.new)
{
if(opps.get(i.OpportunityId).OpportunityLineItems.size()>0)
{
i.addError('Your Message');
}
}
}
Thank you in advance.
I would probably ignore anything related to the Oppty.
You want only one product created, so on creation, either the number of LI is 0 and you can create exactly one, or it' snot 0 and you can't create any.
I would just create a rollup field on the Oppty, count the products. If the count != 0, then fail the validation. If count = 0, then count the Olis in trigger.new and if !=1, fail.
Instead of writing code to do this you should instead create a field on products that stores the id of the parent opportunity, make that field unique, and populate the value via workflow or process builder with the id of the parent opportunity. That way if a second product gets added the unique constraint would fire and prevent the record from being inserted.
Another option would be to create a rollup on opportunity to count the number of opportunity products, then add a validation rule that show an error if the number of products > 1. The advantage of doing it this way is that you get to set the error message as opposed to the generic duplicate error message with the first option.

APEX Trigger when a textfield gets updated

I am trying to create a trigger in APEX, when an custom textfield of an custom sObject gets updated with products (means, when new products get insert or existing one get deleted).
How can I compare in APEX the Trigger.Old values with the Trigger? New values of this field in order to start the Trigger.
It would look something like this:
Trigger NameOfTrigger on CustomSObject__c (after update){
/*there is already an existing list of products that get insert into the custom textfield (probably as Strings)
*/
List <String> textList = new List <String> ();
/*PseudoCode: if the textfield got updated/has changed, copy from every entry of this textfield (entry = product name as a string) and copy fieldX into another sObject
*/
if(CustomSObject.field(OldValues) != CustomSObject.field(NewValues)){
for (String product : textList){
//Trigger e.g. copy the values of a certain field of p and paste them in another sObject
}
Could somebody help me with the syntax?
You can utilize inbuilt Trigger.new and Trigger.old to get the latest and old values of any record. These lists can be used to achieve what you're looking for.
Sample example would be:
Trigger NameOfTrigger on CustomSObject__c (after update){
for(CustomSObject__c customObject : Trigger.new) {
// get old record
CustomSObject__c oldCustomObject = Trigger.oldMap.get(customObject.Id);
// compare old and new values of a particular field
if(customObject.fieldName != oldCustomObject.fieldName){
//Trigger e.g. copy the values of a certain field of p and paste them in another sObject
}
}
}
See documentation of Trigger.new & Trigger.old

Apex code to update new Opportunity with values from related object

What would be the proper method to update a list of new Opportunities with the values from a related record.
for (Opportunity opps:Trigger.new){
[SELECT Id, CorpOwner__r, Contact__r,(SELECT Id, AccountLocation from Account)]
o.CorpOwner__r =Account.Id; o.AccountLocation = opps.Account.AccountLocation;
insert opps
Do you call the lookup fields by the __r suffix? Could you do a before insert operation and still look up the Opportunity.CorpOwner__r relationship to values in the CorpOwner__r Account record, or does that relationship not exist since the record has not been created? What would be a proper batchified way to go about it?
Here's a possibility that demonstrates a number of concepts:
trigger UpdateOpptyWithAccountInfo on Opportunity (before insert) {
// Keep this SOQL query out of the FOR loop for better efficiency/batching
Map<Id, Account> relatedAccounts = new Map<Id, Account>(
[SELECT Id, AccountLocation__c
FROM Account
WHERE Id IN
(SELECT AccountId
FROM Opportunity
WHERE Id = :Trigger.new)
]
);
for (Opportunity o : Trigger.new) {
/* Find each opportunity's Account in the map we queried for earlier
* Note: there's probably a more efficient way to use a Map of Opportunity IDs to Account objects...
* This works fine and could be more readable.
*/
for (Account a : relatedAccounts.values()) {
if (a.Id == o.AccountId) {
// Once you've found the account related to this opportunity, update the values
o.CorpOwner__c = a.Id;
o.AccountLocation__c = a.AccountLocation__c;
}
}
}
// We're still inside an `insert` trigger, so no need to call `insert` again.
// The new fields will be inserted along with everything else.
}
If you're establishing the relationship between objects, use the __c suffix:
o.CorpOwner__c = a.Id; // Associate Account `a` as Opportunity `o`'s CorpOwner
If you're looking up a field on a related object, then you would use __r:
System.debug(o.CorpOwner__r.Name); // Print Opportunity `o`'s CorpOwner's name

Compile error when trying to make rollup apex trigger

Been amending a piece of code to suit my needs but it won't compile. My naive eyes cannot see the error of my ways:
trigger doRollup on Time_Record__c (after insert, after update, after delete, after undelete) {
// List of parent record ids to update
Set<Id> parentIds = new Set<Id>();
// In-memory copy of parent records
Map<Id,Time_Record__c> parentRecords = new Map<Id,Time_Record__c>();
// Gather the list of ID values to query on
for(Daily_Time_Record__c c:Trigger.isDelete?Trigger.old:Trigger.new)
parentIds.add(c.Time_Record_Link__c);
// Avoid null ID values
parentIds.remove(null);
// Create in-memory copy of parents
for(Id parentId:parentIds)
parentRecords.put(parentId,new Time_Record__c(Id=parentId,RollupTarget__c=0));
// Query all children for all parents, update Rollup Field value
for(Daily_Time_Record__c c:[select id,FieldToRoll__c,Time_Record_Link__c from Daily_Time_Record__c where id in :parentIds])
parentRecords.get(c.Time_Record_Link__c).RollupTarget__c += c.FieldToRoll__c;
// Commit changes to the database
Database.update(parentRecords.values());
}
Where:
Time_Record__c is my parent
RollUpTarget__c is the place I am trying to roll to
Daily_Time_Record__c is the child
Time_Record_Link__c is the link to parent that exists on the child
FieldToRoll__c is a test field to roll up on the child
I think that is what I had to replace from this generic template:
trigger doRollup on Child__c (after insert, after update, after delete, after undelete) {
// List of parent record ids to update
Set<Id> parentIds = new Set<Id>();
// In-memory copy of parent records
Map<Id,Parent__c> parentRecords = new Map<Id,Parent__c>();
// Gather the list of ID values to query on
for(Child__c c:Trigger.isDelete?Trigger.old:Trigger.new)
parentIds.add(c.ParentField__c);
// Avoid null ID values
parentIds.remove(null);
// Create in-memory copy of parents
for(Id parentId:parentIds)
parentRecords.put(parentId,new Parent__c(Id=parentId,RollupField__c=0));
// Query all children for all parents, update Rollup Field value
for(Child__c c:[select id,Amount__c,ParentField__c from Child__c where id in :parentIds])
parentRecords.get(c.ParentField__c).RollupField__c += c.Amount__c;
// Commit changes to the database
Database.update(parentRecords.values());
}
Ideally I want to roll up a sum of 7 fields from the child (hence needing this solution), but starting small.

EF4 inheritance and Stored procedures

I implemented inheritance with a discriminator field so all my records are in the same table. My basetype is Person (also the name of the table) and Driver and Passenger inherit from it. I receive instances of the correct type (Driver and Passenger) when I perform a query on the object context to Person. example:
var q = from d in ctx.Person
select d;
But I also create a function that calls a stored procedure and mapped the output of the function to the type Person. But now I get a list of Person and not Drivers or Passengers when I execute this method.
Anybody an idea how to solve this or is this a bug in EF4?
AFAIK, you can't use discriminator mapping (e.g TPH) when dealing with stored procedure mappings.
The stored procedure must be mapped to a complex type or custom entity (e.g POCO), the mapping cannot be conditional.
What you could do is map it to a regular POCO, but then project that result set into the relevant derived type (manual discrimination).
E.g:
public ICollection<Person> GetPeople()
{
var results = ExecuteFunction<Person>(); // result is ObjectResult<Person>
ICollection<Person> people = new List<Person>();
foreach (var result in results)
{
if (result.FieldWhichIsYourDiscriminator == discriminatorForDriver)
{
people.Add((Driver)result);
}
// other discriminators
}
}
If your always expecting a collection of one type (e.g only Drivers), then you wouldn't need the foreach loop, you could just add the range. The above is in case you are expecting a mixed bag of different people types.
Would be interested to see other answers, and if there is a better way though - but the above should work.