trigger LMDofNotes on Note (after insert, after update) {
Id accountId;
Date LMDofNote;
for(Note att: Trigger.new){
accountId = att.ParentId;
LMDofNote= (Date)att.LastModifiedDate;
}
Account acc = [Select Id,LMD_of_Notes__c from Account where Id=:accountId LIMIT 1];
acc.LMD_of_Notes__c = LMDofNote;
update acc;
system.debug('updated date'+LMDofNote);
}
Orgs with Enhanced Notes active do not create Note records, which represents classic Notes.
Instead, they create ContentNote records, which are part of a much more complex ERD. ContentNote doesn't have a ParentId field (its relationship to records is many-to-many), so your trigger would have to be on the ContentDocumentLink object.
ContentNote is basically a facade on the underlying ContentDocument and ContentVersion objects, but you can identify the note records by the FileType field:
All notes have a file type of SNOTE.
Be aware that ContentDocumentLink is used for linking all Content records (not just notes) to sObjects, and that there are unique restrictions on querying it that are described in the documentation linked above.
Related
Trying to just copy the Cost_Price__c field of a product into a custom object when it is updated (if possible inserted too) using an APEX trigger.
I'm so close but the error I am getting at the moment is: Illegal assignment from PricebookEntry to String
trigger updateAccount on Account (after update) {
for (Account oAccount : trigger.new) {
//create variable to store product ID
string productId = oAccount.Product__c;
//SQL statement to lookup price of product using productID
PricebookEntry sqlResult = [SELECT Cost_Price__c
FROM PricebookEntry
WHERE Product2Id =: productId];
//save the returned SQL result inside the field of Industry - Illegal assignment from PricebookEntry to String
oAccount.Industry = sqlResult;
}
}
Am I right in thinking it's because its returning a collective group of results from the SOQL call? I've tried using the sqlResult[0] which still doesn't seem to work.
The Illegal Assignmnet because you are assigning a whole Object i.e PriceBook Entry to a string type of field i.e Industry on Account.
Please use the following code for assignment.
oAccount.Industry = sqlResult[0].Cost_Price__c;
Please mark the answer if this works for you.
Thanks,
Tushar
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.
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
I created a custom object XtendedUser which has an id and Name.
I created a custom lookupfield on Opportunity called "XtendedUser__c" which links the opportunity to the corresponding XtendedUser record.
Now I made it so that the name of an opportunityowner corresponds to the name of an XtendedUser-record, so I want the trigger to autopopulate the custom lookup field "XtendedUser__c" on the opportunity with the id of the corresponding XtendedUser-record of which the name matches the name of the opportunityowner.
I never wrote a trigger, always worked with workflows and fieldupdates, but I've got to make this work. So if you could please help me with this? I would be extremely greatfull!
Thanks in advance
You should use a map to link the records and retrieve the value before the insert of a new record and before the update of an existing record. This technique will also allow you to bulk update all your records. It should be something like:
trigger ExtendedUser__c on Opportunity (before insert, before Update) {
list<id> oid = new list<id>();
for(opportunity o: trigger.new){
oid.add(o.id);
}
map<id, ExtendedUser__c> ExtendU = new map<id, ExtendedUser__c>(
[select name from ExtendedUser__c where id in: oid]);
for(opportunity o: trigger.new){
o.name = ExtendU.get(o.id).name;
}
}
Using LINQ-to-Entities 4.0, is there a correct pattern or construct for safely implementing "if not exists then insert"?
For example, I currently have a table that tracks "user favorites" - users can add or remove articles from their list of favorites.
The underlying table is not a true many-to-many relationship, but instead tracks some additional information such as the date the favorite was added.
CREATE TABLE UserFavorite
(
FavoriteId int not null identity(1,1) primary key,
UserId int not null,
ArticleId int not null
);
CREATE UNIQUE INDEX IX_UserFavorite_1 ON UserFavorite (UserId, ArticleId);
Inserting two favorites with the same User/Article pair results in a duplicate key error, as desired.
I've currently implemented the "if not exists then insert" logic in the data layer using C#:
if (!entities.FavoriteArticles.Any(
f => f.UserId == userId &&
f.ArticleId == articleId))
{
FavoriteArticle favorite = new FavoriteArticle();
favorite.UserId = userId;
favorite.ArticleId = articleId;
favorite.DateAdded = DateTime.Now;
Entities.AddToFavoriteArticles(favorite);
Entities.SaveChanges();
}
The problem with this implementation is that it's susceptible to race conditions. For example, if a user double-clicks the "add to favorites" link two requests could be sent to the server. The first request succeeds, while the second request (the one the user sees) fails with an UpdateException wrapping a SqlException for the duplicate key error.
With T-SQL stored procedures I can use transactions with lock hints to ensure a race condition never occurs. Is there a clean method for avoiding the race condition in Entity Framework without resorting to stored procedures or blindly swallowing exceptions?
You can also write a stored procedure that uses some new tricks from sql 2005+
Use your combined unique ID (userID + articleID) in an update statement, then use the ##RowCount function to see if the row count > 0 if it's 1 (or more), the update has found a row matching your userID and ArticleID, if it's 0, then you're all clear to insert.
e.g.
Update tablex set userID = #UserID, ArticleID = #ArticleID (you could have more properties here, as long as the where holds a combined unique ID) where userID = #UserID and ArticleID = #ArticleID
if (##RowCount = 0)
Begin
Insert Into tablex ...
End
Best of all, it's all done in one call, so you don't have to first compare the data and then determine if you should insert. And of course it will stop any dulplicate inserts and won't throw any errors (gracefully?)
You could try to wrap it in a transaction combined with the 'famous' try/catch pattern:
using (var scope = new TransactionScope())
try
{
//...do your thing...
scope.Complete();
}
catch (UpdateException ex)
{
// here the second request ends up...
}