CRM 2013 Plugin: Setting up new relationship on newly created Accounts - c#

I'm creating a plugin for CRM 2013 (on-premise). My requirement is like this:
When a custom entity "Contract" creates, fire the plugin.
Contract has "1:1" relationship with the Quote entity.
Quote has a 1:N relationship with custom entity 'Property'.
For every properties that Quote has, create new Account records.
Link the newly created Account records to the Contract. The relationship Contract to Account is 1 to N.
I got all working however keep getting problems with #5. For some reason the plugin throws an error that Account ID does not exist.
Here's my code:
foreach ("**Property records found in Quote**")
{
var accountEntity = new Entity();
accountEntity = new Entity("account");
if (record.Attributes.Contains("name"))
{
accountEntity["name"] = record.Attributes["propertyname"];
}
else throw new InvalidPluginExecutionException(OperationStatus.Failed, "New Property Name is needed.");
service.Create(accountEntity);
var referenceCollection = new EntityReferenceCollection();
var relatedEntity = new EntityReference
{
Id = record.Id,
LogicalName = record.LogicalName
};
referenceCollection.Add(relatedEntity);
//The relationship schema name in CRM you are using to associate the entities.
var relRelationship = new Relationship
{
SchemaName = "new_new_contract_account"
};
service.Associate("account", ContractId, relRelationship, referenceCollection);
}

store the id of the newly created account:
var accountid = service.Create(accountEntity);
relatedEntity object must be set with the following properties:
var relatedEntity = new EntityReference
{
Id = accountid, /*the newly created account's id*/
LogicalName = "account"
};
replace your service.Associate line with:
service.Associate("new_contract", ContractId, relRelationship, referenceCollection);

Related

Dynamics 365 (CRM) Version 9.1 online C# code Error: Entity Id must be the same as the value set in property bag

When cloning/copying child records, I use a foreach loop and then create a record with all its attributes. I wrote similar code in another project and worked fine for me.
There are multiple articles/questions based on the same Error. Now my issue is how should I create child records with all its attributes.
foreach (var packingList in oPEntityCollection.Entities)
{
packingList.Attributes.Remove("statuscode");
packingList.Attributes.Remove("statecode");
packingList.Id=Guid.Empty;
orgService.Create(packingList);
}
Another strange issue
An entry with the same key already exists
Code:
Entity parentEntity = orgService.Retrieve(context.PrimaryEntityName, context.PrimaryEntityId, new ColumnSet(true));
parentEntity.Id = Guid.empty;
orgService.Create(parentEntity);
Even if I create a new object and copy parentEntity just like below I get this error.
Entity costcalEntity = new Entity();
costcalEntity = parentEntity;
costcalEntity.Id = Guid.Empty;
orgService.Create(costcalEntity);
So I end up creating a record with primary name and once the record is created, I update the same record with old record attributes.
Entity costcalEntity = new Entity();
costcalEntity.LogicalName = parentEntity.LogicalName;
costcalEntity["name"] = parentQuotationEntity.GetAttributeValue<string>("name");
costcalEntity.Id = Guid.Empty;
Guid newGuid = orgService.Create(costcalEntity);
if (newGuid != Guid.Empty)
{
costcalEntity = parentEntity;
costcalEntity.Id = newGuid;
orgService.Update(costcalEntity);
}
and this works fine.
In both cases you have the same issue, with it's root cause being the Id stored in the attribute collection of the entity. If you look at the early bound generation, you can access the Id by the entity.Id property, as well as the attribute collection as shown in the definition for the id in the primary id:
public System.Nullable<System.Guid> AccountId
{
[System.Diagnostics.DebuggerNonUserCode()]
get
{
return this.GetAttributeValue<System.Nullable<System.Guid>>("accountid");
}
[System.Diagnostics.DebuggerNonUserCode()]
set
{
this.OnPropertyChanging("AccountId");
this.SetAttributeValue("accountid", value);
if (value.HasValue)
{
base.Id = value.Value;
}
else
{
base.Id = System.Guid.Empty;
}
this.OnPropertyChanged("AccountId");
}
}
So when you are retrieving an existing entity, both the Property Id, which you have handled, as well as the attribute collection, which you haven't handled, have been populated by the CRM SDK. So in order to be able to duplicate it, you'll need to clear the id in both places.
Here is how I solved it
foreach (Entity packingList in oPEntityCollection.Entities)
{
Entity newpackingList = new Entity()
{
LogicalName = packingList.LogicalName,
};
newpackingList.Attributes.AddRange(packingList.Attributes);
newpackingList.Attributes.Remove("primaryGuid");
Guid newOpGuid = orgService.Create(newpackingList);
tracingService.Trace($"OP record created sucessfully with guid {newOpGuid}");
}
So the Trick, issue was rather I was trying to assign packingList directly to newpackingList. This caused to assign packingList metadata attributes as well such. This was not acceptable with crm
But rather I should add it's attribute. This worked and created all child records.
Same worked for parent record as well
Entity parentEntity = orgService.Retrieve(context.PrimaryEntityName, context.PrimaryEntityId, new ColumnSet(true));
Entity newParentEntity = new Entity()
{
LogicalName = parentEntity.LogicalName,
};
newParentEntity.Attributes.AddRange(parentEntity.Attributes);
newParentEntity.Attributes.Remove("primaryGuid");
orgService.Create(newParentEntity);
If your question is "How do I duplicate an Entity retrieved from CRM?", your answer can be simplified.
var entity = orgService.Retrieve(context.PrimaryEntityName, context.PrimaryEntityId, new ColumnSet(true));
entity.Id = Guid.Empty;
entity.Attributes.Remove("primaryGuid");
orgService.Create(entity);

Update created record in Custom Workflow Activity -CRM -C#

I have created new entity.
From that entity i call Custom Workflow Activity entity that creates opportunity.
It works, but additionally I have to change some fields on created opportunity.
(I have to add opportunity products, and have to change price list for each opportunity).
As a test I tried to Update account field after creation, but it failed field. When i populate this account field before creation, it works, so it is not about that.
Here is the part of the code:
Entity entity = null;
if (context.InputParameters != null && context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
entity = (Entity)context.InputParameters["Target"];
}
else
{
entity = service.Retrieve(context.PrimaryEntityName, ((Guid)context.PrimaryEntityId), new ColumnSet(true));
}
Entity opportunity = new Entity("opportunity");
string name = entity.GetAttributeValue<string>("subject");
opportunity["name"] = name;
opportunityId = service.Create(opportunity);
EntityReference accountlookup = (EntityReference)entity.Attributes["ad_sendto"];
Guid accountId = accountlookup.Id;
opportunity["parentaccountid"] = new EntityReference("account", accountId);
service.Update(opportunity);
To repeat, it creates opportunity, but it doesn't work for update, is there any other way to do this, or do I have some errors here?
It fails because you are trying to update opportunity entity which does not have a primary key (opportunityid) set.
Instead of updating the opportunity after it was created, why not just assign the parentaccountid during the create operation?
var opportunity = new Entity("opportunity");
opportunity["name"] = entity.GetAttributeValue<string>("subject"); ;
opportunity["parentaccountid"] = entity.Attributes["ad_sendto"];
opportunityId = service.Create(opportunity);
For future references, if you ever have to update an entity that was just created or any entity for that matter:
var opportunityToUpdate = new Entity("opportunity")
{
Id = opportunityId
};
opportunityToUpdate["parentaccountid"] = entity.Attributes["ad_sendto"];
service.Update(opportunityToUpdate);

assigning a lead to customer field in Phonecall activity

My code generates leads in Microsoft dynamics CRM system. There are phone call activities associated with leads. There are "To" and "From" properties in the phone call activities which can be either a contact or lead. I need my code to assign the lead to those properties. I implemented this:
Entity account = new Entity("lead");
lead_id= service.Create(account);
Entity activity1 = new Entity("phonecall");
activity1["description"] = "Phone call activity";
activity1["to"]=account;
activity1.Attributes.Add("regardingobjectid", new EntityReference("lead", lead_id));
service.Create(activity1);
It doesn't show any error but doesn't work. I can see that the "to" field in the activity is empty in CRM system.
public static Guid createActivity(Guid lead_id, Entity sendr, Entity recvr)
{
Entity activity1 = new Entity("phonecall");
activity1["description"] = ImgURL;
var activityParty1 = new Entity("activityparty");
activityParty1["partyid"] = sendr.ToEntityReference();
activity1["from"] = new[] { activityParty1 };
var activityParty = new Entity("activityparty");
activityParty["partyid"] = recvr.ToEntityReference();
activity1["to"] = new[] { activityParty };
activity1.Attributes.Add("regardingobjectid", new EntityReference("lead", lead_id));
Guid acc_id = service.Create(activity1);
return acc_id;
}
Exception at: Guid acc_id = service.Create(activity1);
Activity Party is the connection between PhoneCall and related "to" field. Create an add an activity party.
Early Bound:
activity1.To = new[]
{
new ActivityParty() {PartyId = account.ToEntityReference()}
};
Late Bound:
var activityParty = new Entity("activityparty");
activityParty["partyid"] = account.ToEntityReference();
activity1["to"] = new[] {activityParty};
You should reference an EntityReference every time to want to associate entities. More, the entity you're associating with should already exist.
So you can rewrite your code as:
Entity account = new Entity("lead");
lead_id= service.Create(account);
Entity activity1 = new Entity("phonecall");
activity1["description"] = "Phone call activity";
activity1["to"]=**account.ToEntityReference()**;
activity1["regardingobjectid"] = **account.ToEntityReference()**;
service.Create(activity1);

EntityFramework and DbContext, transforming an entity to a DTO and back

Some Background Information first:
I have a server that provides wcf soap services and a website that consumes those services. The server uses the entity framework to write/read to/from the database. During the process the entity object are transformed into DTOs and back when they return to the server.
I have the following entity model:
The DTOs are autogenerated.
Now to the problem:
The Participent is the 'start' object that is created with a VisibleStatus, a Status, a StatusMessage and two ContactGroups. After those are created I want to add Contact with the already created Participent and ContactGroup.
The problem here is, that the entity framework does not realize that the participent and the contact group already exist in the database and it creates a new database entry for those. Even if they already have an id. I think the problem lies in the fact that the entities are transformed to DTOs and back.
Asume the following client side code to generate the participent, visible status, status, status message and contact groups:
MT_Stammdaten_MeineKontakte_ParticipentDTO user = new MT_Stammdaten_MeineKontakte_ParticipentDTO();
user.MT_Participant_Id = endUserId;
user.StatusMessage = new StatusMessageDTO()
{
Text = "not defined",
Timestamp = DateTime.Now,
};
user.VisibleStatus = new VisibleStatusDTO()
{
Photo = null,
Status = new StatusDTO()
{
Value = "not defined"
},
Timestamp = DateTime.Now
};
user = cClient.AddParticipantMapping(user);
ContactGroupDTO defaultGroup = new ContactGroupDTO()
{
Name = CONTACTS_GROUP_STANDARD,
Description = CONTACTS_GROUP_STANDARD_DESC,
Participent = user,
};
ContactGroupDTO familyGroup = new ContactGroupDTO()
{
Name = CONTACTS_GROUP_FAMILY,
Description = CONTACTS_GROUP_FAMILY_DESC,
Participent = user,
};
defaultGroup = cClient.AddContactGroup(defaultGroup);
familyGroup = cClient.AddContactGroup(familyGroup);
And now the code for creating the contact:
MT_Stammdaten_MeineKontakte_ParticipentDTO participent = cClient.getUser(endUserId);
ContactGroupDTO group = cClient.GetContactGroup(1);
MT_Stammdaten_MeineKontakte_EndUser endUser = new MT_Stammdaten_MeineKontakte_EndUser()
{
MT_EndUser_Id = newContactId,
};
ContactDTO contact = new ContactDTO()
{
ContactGroup = group,
ContactGroupId = group.Id,
MT_Stammdaten_MeineKontakte_EndUser = endUser,
MT_Stammdaten_MeineKontakte_Participent = participent,
}
contact = cClient.AddContact(contact);
How can one tell the entity framework that the objects with an id already exist? Because of the fact, that most of the objects are nested, I'd prefer a rather generic solution.
You need to set the State on the existing objects to EntityState.Unchanged.
eg, for a group
context.ObjectStateManager
.ChangeObjectState
(group, System.Data.EntityState.Unchanged);

How to create and delete data from entity relationship many-to-many in CRM 2011?

How to create and delete data from entity relationship many-to-many in crm 2011?
Code:
QueryExpression qry = new QueryExpression();
qry.EntityName = "entity1_entity2";
qry.ColumnSet = new ColumnSet(true);
var re = crmservice.RetrieveMultiple(qry).Entities;
crmservice.Delete("entity1_entity2", re[0].Id);
FaultException: The 'Delete' method does not support entities of type 'entity1_entity2'.
In order to link two records via a N:N relationship, you have to use the Associate/Disassociate request or the corresponding methods of the service proxy.
This will create/delete the corresponding record of the entity1_entity2 entity.
using Microsoft.Crm.Sdk.Messages;
...
// get the crm service
...
AssociateEntitiesRequest fooToBar = new AssociateEntitiesRequest
{
Moniker1 = foo, // foo is an entity reference
Moniker2 = bar, // bar is an entity reference
RelationshipName = "foo_bar", // name of the relationship
}
service.Execute(fooToBar) // relates foo and bar
Here's a blog post: http://charithrajapaksha.blogspot.com/2011/08/creating-many-to-many-records-in-crm.html
For Delete you try below
// Create an AssociateEntities request.
//Namespace is Microsoft.Crm.Sdk.Messages
DisassociateEntitiesRequest request = new DisassociateEntitiesRequest();
// Set the ID of Moniker1 to the ID of the lead.
request.Moniker1 = new EntityReference
{
Id = moniker1.Id,
LogicalName = moniker1.Name
};
// Set the ID of Moniker2 to the ID of the contact.
request.Moniker2 = new EntityReference
{
Id = moniker2.Id,
LogicalName = moniker2.Name
};
// Set the relationship name to associate on.
request.RelationshipName = strEntityRelationshipName;
// Execute the request.
service.Execute(request);
In N:N Relationships the records should be associated and disassociated. you can't create and delete records in N:N Relationship. you can use AssociateRequest, DisassociateRequest classes or you can use Associate, Disassociate Messages in Plugin Registration tool.

Categories

Resources