I'm fairly new to developing but I've encountered a problem when creating a plugin for Dynamics CRM. The plugin is supposed to render the parentcustomerid field null on contact entity when the account entity it is linked to is updated when the field primarycontactid is updated to something else, either that be null on linked to another contact.
With the code I have written currently no errors are thrown and the code is executed successful but parentcustomerid field still contains the account it is linked too when it should remove the link.
Here is the code i have currently:
public void Execute(IServiceProvider serviceProvider)
{
ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
//Obtain the execution context
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
//obtain organizational services
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
EntityReference prePCID;
Entity PreImage;
// The InputParameters collection contains all the data passed in the message request.
if (context.InputParameters.Contains("Target") &&
context.InputParameters["Target"] is Entity)
{
// Obtain the image entity from the Pre Entity Images.
tracingService.Trace
("trace1: Getting the target entity from Input Parameters.");
PreImage = (Entity)context.InputParameters["Target"];
// Verify that the target entity represents an account.
// If not, this plug-in was not registered correctly.
tracingService.Trace
("trace2: Verifying that the target entity represents a account.");
if (PreImage.LogicalName == "account")
{
if (PreImage.Attributes.Contains("primarycontactid"))
{
tracingService.Trace
("trace3: Setting the primary contact id in the prePCID.");
//prePCID = (EntityReference)PreImage.Attributes["primarycontactid"];
prePCID = (EntityReference)PreImage["primarycontactid"];
tracingService.Trace
("trace4: Primary Contact Name: " + prePCID.Name + " Creating a variable that stores the contact using the prePCID.");
Entity contactToRemoveReference = service.Retrieve("contact", prePCID.Id, new ColumnSet("parentcustomerid")) as Entity;
tracingService.Trace
("trace5: Removes the id: " + prePCID.Id + " of the parentcustomerid.");
contactToRemoveReference.Attributes["parentcustomerid"] = null;
service.Update(contactToRemoveReference);
tracingService.Trace
("trace6: Execution Successful.");
}
}
}
}
If anyone could solve this issue for me, that would be great thanks.
You are populating Entity variable PreImage from primary entity in the input parameters.
I think you should get it from Pre image like:
Entity PreImage;
if (context.PreEntityImages.Contains("yourPreImageName") && context.PreEntityImages["yourPreImageName"] != null)
{
PreImage = context.PreEntityImages["yourPreImageName"];
}
Related
Hi I'm new to Dynamics and plugins in dynamics. I have created a simple Entity called Library that holds books.
After a new book is created I want the price of the book to increment by a GST of 10% on the server side via a plugin.
I know this would normally occur on the page before saving by I'm trying to work out how server side logic works.
I have created a postOperation (synchronous) step for the "Create" message to call the Plugin Execute() method. From my reading this should occur AFTER the record is saved in the database.
I also have a post image entity that I access.
In the Execute method I try to access the saved record via the PostMessageEntity to update the price, but I get an exception saying the record does not exist based on the record identifier that i have obtained. I can confirm the record was never created in the system, yet the postOperation has been called.
How do I access the just saved record in the plugin so that I can update the Price?
My code:
public void Execute(IServiceProvider serviceProvider)
{
// Obtain the execution context from the service provider.
Microsoft.Xrm.Sdk.IPluginExecutionContext context = (Microsoft.Xrm.Sdk.IPluginExecutionContext)
serviceProvider.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext));
// create a trace log so you can see where in the code it breaks
ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
// create access to service
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
tracingService.Trace("have reached execute event in plugin.");
// The InputParameters collection contains all the data passed in the message request.
if (context.InputParameters.Contains("Target") &&
context.InputParameters["Target"] is Entity)
{
tracingService.Trace("We have a target and it is an entity.");
// Obtain the target entity from the input parameters.
Entity entity = (Entity)context.InputParameters["Target"];
if (entity.LogicalName == "new_books")
{
tracingService.Trace("the entity id of the record that was created is .." + entity.Attributes["new_booksid"].ToString());
// do we have a post update image of the new_books entity
if (context.PostEntityImages.Contains("newbookpostImage") && context.PostEntityImages["newbookpostImage"] is Entity)
{
tracingService.Trace("we have a postEntityImage.");
// // yep lets grab it.
Entity postMessageEntity = (Entity)context.PostEntityImages["newbookpostImage"];
// get book price as just saved to db
decimal bookPrice = ((Money)postMessageEntity.Attributes["new_price"]).Value;
// get id of the the record we have
Guid RecordID = ((Guid)postMessageEntity.Attributes["new_booksid"]);
tracingService.Trace("we have a post update bookprice.");
tracingService.Trace("the entity id of the post image entity is ..." + postMessageEntity.Attributes["new_booksid"].ToString());
Entity created_book = new Entity("new_books");
// use service to access a field of the current record as it is in the database and column we want to update.
created_book = service.Retrieve(created_book.LogicalName, RecordID, new ColumnSet(true));
//And the last line is where it dies and tells me new_books with id with d7bfc9e2 - 2257 - ec11 - 8f8f - 00224814e6e0 does not exist.
}
}
}
}
Entity postMessageEntity = (Entity)context.PostEntityImages["newbookpostImage"];
Is your PostEntityImage new_books entity?
Also if you have an entity postMessageEntity you can directly get Entity Record ID by
postMessageEntity.ID
rather than Guid RecordID = ((Guid)postMessageEntity.Attributes["new_booksid"]);
Here your code does nothing more than create empty object of type Entity new_books.
You have not set Priamry name field of entiy or any other. Also you have not created a record, you should use
Entity created_book = new Entity("new_books")
service.Create(created_book);
Below you are trying to fecth Record from Entity new_books based on postMessageEntity.Id
You should check postMessageEntity logical name is same as created_book.LogicalName and then use postMessageEntity.ID rather than RecordID
created_book = service.Retrieve(created_book.LogicalName, RecordID, new ColumnSet(true));
In the plugin pipeline you can actually add, modify and even remove attributes in the entity object on the fly. This must be done before the main operations take place: in the prevalidation or in the preoperation stage.
So, your code can be simplified like this:
public void Execute(IServiceProvider serviceProvider)
{
var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
Debug.Assert(context.Stage <= 20); // This only works in prevalidation and preoperation stages.
var book = (Entity)context.InputParameters["Target"]; // For message Create a Target parameter is always available.
// Using GetAttributeValue is more safe, because when price is not set, the attribute will not be available in the collection.
decimal? price = book.GetAttributeValue<Money>("new_price")?.Value;
if (price.HasValue)
book["new_price"] = new Money(price.Value * 1.1M);
}
In the synchronous post create stage you are still in a database transaction. At that point the record is created, but not yet committed.
The ID of the record created can be found in the OutputParameters collection. You can pick it up like this:
var recordId = (Guid)context.OutputParameters["id"];
There is no need to do checks on the context object. When your plugin is registered properly, all items you would expect to be available will be there. If not, a proper exception log will be your best friend. Just add a generic exception handler responsible for writing the error context to the plugin trace log.
I'm using Microsoft Dynamics CRM 2016 on-premise version.
I have an "account" entity which has associated "contacts". When the current "account" entity's "address" is updated, I want all the associated contacts addresses to be updated with that address.
I want to do this in a plug-in which runs on the "account" entity when you update the address. When you do so, ALL the associated contacts have their address updated to that address.
I've done a bit of searching for this, but there's nothing out there which shows the ADDRESS getting updated. The examples out there typically show, for example, a phone number being updated. What makes the address more complicated is that the addresses are stored in an address entity, so I think I have to get an addressId primary key of some kind and put that in each of the associated contacts address FK field. I've no idea how and can't find any similar examples.
Does anyone have a snippet of code that will go into the plugin?
[NB I'm planning on putting it in the public void Execute(IServiceProvider serviceProvider) method in the plugin code.]
You do not need the id of a contact's address when updating it. Two types of addresses are already incorporated in the contact entity. They are typically used for postal and visit addresses. The address field names are prefixed with address1_ and address2_. So, just set these fields like this on the contact entity:
contact["address1_line1"] = "John Doe";
A plugin could look like this:
public class AccountPlugin : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
var factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
var orgService = factory.CreateOrganizationService(null);
var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
Entity account = context.PostEntityImages.First().Value;
var query = new QueryExpression("contact");
query.Criteria.AddCondition("accountid", ConditionOperator.Equal, context.PrimaryEntityId);
var result = orgService.RetrieveMultiple(query);
foreach (Entity contact in result.Entities)
{
contact["address1_line1"] = account.GetAttributeValue<string>("address1_line2");
orgService.Update(contact);
}
}
}
Register it on the post update message on entity account and add a post entity image to the step.
Thanks to Henk Van Boeijen's excellent answer above, I post the following code (which is Henk's code posted into my plug-in).
Here is the code for a plugin which will update all of the addresses for all of the contacts connected to an organisation, when you update the organization's address.
Note that in this example, the Organization entity has been called Account.
This is to help anyone in future who needs to accomplish this.
public class UpdateContactAddresses : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
// Create a tracing instance to log progress of this plugin.
ITracingService tracing = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
try
{
// Obtain the execution context from the service provider.
IPluginExecutionContext pluginExecutionContext = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
// Obtain the organization service reference.
IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = factory.CreateOrganizationService(null);
if (pluginExecutionContext.InputParameters.Contains("Target") && pluginExecutionContext.InputParameters["Target"] is Entity)
{
// Obtain the target entity from the input parameters.
Entity account = (pluginExecutionContext.InputParameters["Target"] as Entity);
// Verify that the target entity represents an account. If not, this plug-in was not registered correctly.
if (account.LogicalName != "account")
{
tracing.Trace("This entity is not an Account entity. It is likely that this plug-in was not registered correctly (was an incorrect \"Primary Entity\" selected? It should be an Account entity).");
return;
}
var query = new QueryExpression("contact");
query.Criteria.AddCondition("accountid", ConditionOperator.Equal, pluginExecutionContext.PrimaryEntityId);
var result = service.RetrieveMultiple(query);
tracing.Trace("The QueryExpression found " + result.TotalRecordCount.ToString() + " associated contacts.");
foreach (Entity contact in result.Entities)
{
tracing.Trace("Updating contact " + contact.ToString() + " address...");
contact["address1_line1"] = account.GetAttributeValue<string>("address1_line1");
contact["address1_line2"] = account.GetAttributeValue<string>("address1_line2");
contact["address1_line3"] = account.GetAttributeValue<string>("address1_line3");
contact["address1_city"] = account.GetAttributeValue<string>("address1_city");
contact["address1_county"] = account.GetAttributeValue<string>("address1_county");
contact["address1_postalcode"] = account.GetAttributeValue<string>("address1_postalcode");
contact["address1_country"] = account.GetAttributeValue<string>("address1_country");
service.Update(contact);
tracing.Trace("Contact " + contact.ToString() + " address updated.");
}
}
tracing.Trace("Completed execution of plugin " + this.GetType().Name + ".");
}
catch (FaultException<OrganizationServiceFault> ex)
{
throw new InvalidPluginExecutionException("An error occurred in plugin " + this.GetType().Name + ".", ex);
}
catch (Exception ex)
{
tracing.Trace("An error occurred executing plugin " + this.GetType().Name + ".");
tracing.Trace("\t\tError: " + ex.Message);
throw ex;
}
}
}
I am what you call a "n00b" in CRM plugin development. I am trying to write a plugin for Microsoft's Dynamics CRM 2011 that will create a new activity entity when you create a new contact. I want this activity entity to be associated with the contact entity.
This is my current code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xrm.Sdk;
namespace ITPH_CRM_Deactivate_Account_SSP_Disable
{
public class SSPDisable_Plugin: IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
// Obtain the execution context from the service provider.
IPluginExecutionContext context = (IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
if (context.InputParameters.Contains("Target") && context.InputParameters["target"] is Entity)
{
Entity entity = context.InputParameters["Target"] as Entity;
if (entity.LogicalName != "account")
{
return;
}
Entity followup = new Entity();
followup.LogicalName = "activitypointer";
followup.Attributes = new AttributeCollection();
followup.Attributes.Add("subject", "Created via Plugin.");
followup.Attributes.Add("description", "This is generated by the magic of C# ...");
followup.Attributes.Add("scheduledstart", DateTime.Now.AddDays(3));
followup.Attributes.Add("actualend", DateTime.Now.AddDays(5));
if (context.OutputParameters.Contains("id"))
{
Guid regardingobjectid = new Guid(context.OutputParameters["id"].ToString());
string regardingobjectidType = "account";
followup["regardingobjectid"] = new EntityReference(regardingobjectidType, regardingobjectid);
}
service.Create(followup);
}
}
}
But when i try to run this code: I get an error when i try to create a new contact in the CRM environment. The error is: "The given key was not present in the dictionary" (Link *1). The error pops up right as i try to save the new contact.
Link *1: http://puu.sh/4SXrW.png
(Translated bold text: "Error on business process")
Microsoft Dynamics CRM uses the term activity to describe several types of interactions. The types of activities are:
Phone Call, Task, E-mail, Letter, Fax and Appointment.
ActivityPointer (Activity) Entity
To make your code working Replace the following line:
Entity followup = new Entity();
with
Entity followup = new Entity("task");
And remove the following line:
followup.LogicalName = "activitypointer";
Also please read my comment and Guido Preite's commend above. You need to modify your code to make it working with contact.
Edited
Make sure ContactId does exist in CRM before referencing it to Activity.
This can often happen if you are explicity adding an attribute value to the target entity in you plugin where it already has been added.
Rather than entity.Attributes.Add(...)
use entity["attributename"] = ...
In CRM when emails arrive and have the tracking token in them they automatically set the regarding field to be the incident (or whatever they relate to)
Unfortunately the Record wall isn't updated with this info so even if you are following the case nothing alerts you to the new activity.
I want to write a plugin on email or incident (or both) that updates the record wall and creates a task to follow up on that email with in 3 days.
I'm looking at the SDK and I can't see what the appropriate event in the pipe line would be to work out when an email is/has its regarding field set on arrival in the CRM.
The CRM email creation life-cycle is not well described in the documentation. [shakes fist]
Extra things that are bothering me
I can't seem to include a reference to get a strongly typed Email, Post or Case (driving me crazy)
Testing this is really hard (harder than it should be)
EDIT Here is my current code
namespace Assembly.Plugins
{
using System;
using System.ServiceModel;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
/// <summary>
/// PostEmailDeliverIncoming Plugin.
/// </summary>
public class PostEmailDeliverIncoming : Plugin
{
/// <summary>
/// Initializes a new instance of the <see cref="PostEmailDeliverIncoming"/> class.
/// </summary>
public PostEmailDeliverIncoming()
: base(typeof(PostEmailDeliverIncoming))
{
RegisteredEvents.Add(new Tuple<int, string, string, Action<LocalPluginContext>>(40, "DeliverIncoming", "email", ExecutePostEmailDeliverIncoming));
// Note : you can register for more events here if this plugin is not specific to an individual entity and message combination.
// You may also need to update your RegisterFile.crmregister plug-in registration file to reflect any change.
}
protected void ExecutePostEmailDeliverIncoming(LocalPluginContext localContext)
{
if (localContext == null)
{
throw new ArgumentNullException("localContext");
}
//Extract the tracing service for use in debugging sandboxed plug-ins.
ITracingService tracingService = localContext.TracingService;
// Obtain the execution context from the service provider.
IPluginExecutionContext context = localContext.PluginExecutionContext;
// Obtain the organization service reference.
var service = localContext.OrganizationService;
// The InputParameters collection contains all the data passed in the message request.
if (!context.InputParameters.Contains("Target") || !(context.InputParameters["Target"] is Entity))
return;
// Obtain the target entity from the input parmameters.
var target = (Entity)context.InputParameters["Target"];
// Verify that the target entity represents an account.
// If not, this plug-in was not registered correctly.
if (target.LogicalName != "email")
return;
if((string)target["direction"] != "Incoming")
return;
if (target["regardingobjectid"] == null)
return;
try
{
// if its not a case I don't care
var incident = service.Retrieve("incident", (Guid)target["regardingobjectid"], new ColumnSet(true));
if (incident == null)
return;
var post = new Entity("post");
post["regardingobjectid"] = target["regardingobjectid"];
post["source"]=new OptionSetValue(0);
post["text"] = String.Format("a new email has arrived.");
// Create the task in Microsoft Dynamics CRM.
tracingService.Trace("FollowupPlugin: Creating the post.");
service.Create(post);
// Create a task activity to follow up with the account customer in 7 days.
var followup = new Entity("task");
followup["subject"] = "Follow up incoming email.";
followup["description"] = "An email arrived that was assigned to a case please follow it up.";
followup["scheduledstart"] = DateTime.Now.AddDays(3);
followup["scheduledend"] = DateTime.Now.AddDays(3);
followup["category"] = context.PrimaryEntityName;
// Refer to the email in the task activity.
if (context.OutputParameters.Contains("id"))
{
var regardingobjectid = new Guid(context.OutputParameters["id"].ToString());
followup["regardingobjectid"] = new EntityReference("email", regardingobjectid);
}
// Create the task in Microsoft Dynamics CRM.
tracingService.Trace("FollowupPlugin: Creating the task activity.");
service.Create(followup);
}
catch (FaultException<OrganizationServiceFault> ex)
{
throw new InvalidPluginExecutionException("An error occurred in the FollupupPlugin plug-in.", ex);
}
catch (Exception ex)
{
tracingService.Trace("FollowupPlugin: {0}", ex.ToString());
throw;
}
}
}
}
I've just been fighting with this exact same issue and came across this post. I thought I'd post the solution for you (if you still need it) and anyone else who comes across the issue in the future.
Here's the solution I arrived at:
- Using the Plugin Registration Tool register a New Image on the appropriate step( Stage = "40", MessageName = "DeliverIncoming")
- Set the New Image to be a Post Image
- In your plugin fetch the Post Image's entity ID:
Guid emailID = context.PostEntityImages["PostImage"].Id;
Entity emailFromRetrieve = localContext.OrganizationService.Retrieve(
"email",
emailID,
new Microsoft.Xrm.Sdk.Query.ColumnSet(true));
Email email = emailFromRetrieve.ToEntity<Email>();
if (email.RegardingObjectId == null)
{
return;
}
var regardingObject = email.RegardingObjectId;
Hope this helps!
I'm actually working on a very similar plugin at the moment. Mine creates a custom entity upon arrival of an email addressed to a certain email address. It also associates the incoming email with that new record via the Regarding field. I've added a Pre-Operation step on Create of Email and it works great, including incoming email from the router.
What I'm not sure of is when CRM fills in the Regarding field. You might look at Post-Operation and see if it is set there?
One interesting caveat regarding the Regarding field (haha!): Unlike single lookup fields, the Regarding object's name is actually stored in the ActivityPointer table, so when you update the Regarding field, be sure to set the Name on the EntityReference. If you don't, the Regarding lookup will still have a clickable icon but there won't be any text. I do it like this:
email.RegardingObjectId = [yourentity].ToEntityReference();
email.RegardingObjectId.Name = email.Subject;
Hope that helps!
I ended up doing this in a workflow on the email entity
Steps
Create new workflow, I called it 'incoming email workflow'
Scope is Organisation
Choose Email as the entity and check 'Record field changes'
Add a step that checks Regarding (Case):Case Contains Data
if true:
Add a step that creates a Post
Edit the properties in the Post
Text : This case has had {Direction(E-mail)} email activity from {From(E-mail)}
Source : Auto Post
Regarding : {Regarding(E-mail)}
Add a step that creates a Task
Edit the properties in the Task
Subject : Follow up {Subject(E-mail)}
Regarding : {Regarding(E-mail)}
Try to use the following code:
if ((bool)entity["directioncode"] == false)
Instead of your code:
if((string)target["direction"] != "Incoming")
I'm trying to associate related records of an entity to a newly created one. The pluggin triggers on creation and pre-operation.
The error occurs when trying to associate the collection to the new entity : "new_ligneContrat With Id = ad630ba6-684e-e111-92e3-00155d151905 Does Not Exist"
Here is my code :
public void Execute(IServiceProvider serviceProvider)
{
// Instanciation des services
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = factory.CreateOrganizationService(null);
Entity target = (Entity)context.InputParameters["Target"];
EntityReference contrats = (EntityReference)target.Attributes["new_contratsid"];
FetchExpression fetch = new FetchExpression(#"
<fetch distinct='false' mapping='logical'>
<entity name='" + context.PrimaryEntityName + "'><link-entity name='new_contrats' alias='nombreligne' from='new_contratsid' to='new_contratsid'><filter type='and'><condition attribute='new_contratsid' value='" + contrats.Id + "' operator='eq'></condition></filter></link-entity></entity></fetch>");
EntityCollection lines = service.RetrieveMultiple(fetch);
// Vérification qu'il y a au moins une ligne de contrat associée
if (lines.Entities.Any())
{
var first = lines.Entities.Last();
if (first.GetAttributeValue<OptionSetValue>("statecode").Value == 1)
{
FetchExpression query = new FetchExpression(#"
<fetch distinct='false' mapping='logical'>
<entity name='incident'><filter type='and'><condition attribute='new_lignecontrat' value='"+first.Id+"' operator='eq'/></filter></entity></fetch>");
EntityCollection incident = service.RetrieveMultiple(query);
if (incident.Entities.Any())
{
foreach (var e in incident.Entities)
{
e.Attributes["new_lignecontrat"] = new EntityReference (target.LogicalName, target.Id);
}
}
}
}
What is wrong???
Thanks in advance!!
Edit 1: ok seems logical since the record does not exist yet ><. Just one thing : How can I change the value of a lookup field? What is its type?
Edit 2: I've got no error when executing my code, but fields of the incident entity do not update ><'....I've tested my code with invalidPluginExceptions and the end of the code is reached...Here is the code :
Edit 3 : Code updated...
To answer your original question and its edit, yeah, you can't associate the record with another record when the core database operation hasn't been done yet.
Pre-operation: Stage in the pipeline for plug-ins that are to execute before the main
system operation. Plug-ins registered in this stage are executed
within the database transaction.
So to handle association, you can either change the stage to post-operation, or have one IPlugin class handle the pre-operation stage and another handle the post-operation stage, either in one or multiple projects.
To answer the edit, lookup fields are of the class EntityReference. (Looks like you're working with a 1:N relationship?)
To answer the second edit, I don't see anywhere in your code snippet where you assign the new EntityReference to your target Entity. Moreover, you don't have to issue an Update request to the service in the pre-operation stage because the core database operation has not been performed yet. You can just set the attribute of the Entity to be equal to the the value of your choice, and this change will be carried over to the database.
if (entity.Attributes.ContainsKey("new_lignecontrat"))
{
entity.Attributes["new_lignecontrat"] = YourEntityReference;
}
else //attribute not included in the plugin operation
{
entity.Attributes.Add("new_lignecontrat", YourEntityReference);
}
Microsoft has a demonstration of this concept in the SDK: \sdk\samplecode\cs\plug-ins\accountnumberplugin.cs