How do I do that?
I need to import (and map) a CSV file to a custom entity in CRM 2011.
I am running an on-premise instance of CRM 2011 and need to use the late bound entities approach.
I have already tried following this example: Export and import a data map but failed miserably (ImportMap not found - what assembly is it in?).
Hi you can do something like below programatically, without creating early-bound classes.
using (StreamReader reader = new StreamReader("D://yourfileFolder//file.txt"))
{
string line;
while ((line = reader.ReadLine()) != null && line!=String.Empty)
{
var values = line.Split(','); //your data separator, it could be any character
Entity customEntity = new Entity("entityLogicalName");
//you should adjust the values according to the data-type on Dynamics CRM e.g
// customEntity ["revenue"] = new Money(values[0].ToString());
customEntity ["field1"] = values[0];
customEntity ["field2"] = values[1];
customEntity ["field3"] = values[2];
orgService.Create(customEntity);
}
}
ImportMap is an entity in CRM rather than a class in the SDK Assemblies. To get that example code to compile you'll need to have a class that represents the ImportMap entity, which is the early-bound model of CRM programming.
You can find the class ImportMap in the file MyOrganizationCrmSdkTypes.cs in the SDK. Adding that file to your project will give you early bound classes for all the out-of-box entities. Alternatively, you could use CrmSvcUtil (included with the SDK), or a 3rd party tool (such as Daryl Labar's or XrmToolkit) to generate just the ImportMap early-bound class.
Related
Due to some bad practices from one of our internal users. We need to transfer all activities (mails, notes, etc) from one contact to another contact. I was trying to achieve this via UI and I could not find a way to do this.
Is this possible? I'm looking for any way to achieve this, wether is CRMTool, SSIS, UI or any other way. Only admins will do this so we do not need anything fancy as it will be done maybe 4 times a year to clean up some data.
Thanks a lot :)
Tried using UI but no success.
I can think of two ways to do these updates.
The first method is selecting a view on an activity where the owner is listed (i.e. All Phone Calls) and exporting to Excel. This downloads a XLSX with some hidden columns at the start where IDs for the records are kept. You then update the owner column with the new owner (take care of copying the exact fullname), and then importing the Excel spreadsheet again. You would need to repeat this export/import steps for each activity type (phone calls, email, etc.). So this might be impractical if you have a large volume of date, because of the need to repeat and because there are max numbers of records that you can export.
The other way to do this is using some .NET code. Of course, to do this you will need to use Visual Studio 2019.
If that's the case, this will do the trick:
using System;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Tooling.Connector;
namespace ChangeActivitiesOwner
{
class Program
{
static void Main(string[] args)
{
string connectionString = "AuthType=Office365;Url=<TODO:URL>;Username=<TODO:User>;Password=<TODO:Pass>;";
string oldUserFullname = ""; // TODO: place here fullname for the user you want to overwrite
string newUserFullname = ""; // TODO: place here fullname for the user you want to overwrite with
CrmServiceClient client = new CrmServiceClient(connectionString);
IOrganizationService service = client.OrganizationWebProxyClient != null ? client.OrganizationWebProxyClient : (IOrganizationService)client.OrganizationServiceProxy;
QueryByAttribute qbyaOldUser = new QueryByAttribute("systemuser");
qbyaOldUser.AddAttributeValue("fullname", oldUserFullname);
Guid olduserid = (Guid)service.RetrieveMultiple(qbyaOldUser)[0].Attributes["systemuserid"];
QueryByAttribute qbyaNewUser = new QueryByAttribute("systemuser");
qbyaNewUser.AddAttributeValue("fullname", newUserFullname);
Guid newuserid = (Guid)service.RetrieveMultiple(qbyaNewUser)[0].Attributes["systemuserid"];
foreach (string activity in new string[]{ "task", "phonecall", "email", "fax", "appointment", "letter", "campaignresponse", "campaignactivity" }) // TODO: Add other activities as needed!!!
{
QueryExpression query = new QueryExpression(activity)
{
ColumnSet = new ColumnSet("activityid", "ownerid")
};
query.Criteria.AddCondition(new ConditionExpression("ownerid", ConditionOperator.Equal, olduserid));
foreach (Entity e in service.RetrieveMultiple(query).Entities)
{
e.Attributes["ownerid"] = new EntityReference("systemuser", newuserid);
service.Update(e);
}
}
}
}
}
Please complete the lines marked with "TODO" with your info.
You will need to add the packages Microsoft.CrmSdk.CoreAssemblies, Microsoft.CrmSdk.Deployment, Microsoft.CrmSdk.Workflow, Microsoft.CrmSdk.XrmTooling.CoreAssembly, Microsoft.IdentityModel.Clients.ActiveDIrectory and Newtonsoft.Json to your solution, and use .NET Framework 4.6.2.
Hope this helps.
i have a wcf which connects to crm (on prem) to retrieve an account record. i can see when the entity is retrieved it does not hold the current record i.e. some field will still hold the old column value. i tried with various merge option with no avail. please see the code below
using (XrmServiceContext cContext = new XrmServiceContext(con))
{
Entity ent = cContext.Retrieve(ConstantKVP.AccountSchema.ENTITY_LOGICAL_NAME, AccountId, new ColumnSet(true));
}
any suggestions?
Is it possible the data is being cached?
cContext.TryAccessCache(cache => cache.Mode = OrganizationServiceCacheMode.Disabled);
I took this approach for a CrmOrganizationServiceContext, so perhaps the same theory applies.
After save use clear changes cContext.ClearChanges();
For retrieves use MergeOption.OverwriteChanges
Or
Create a new XrmServiceContext object by passing a newed up organizationservice:
var uncachedOrganizationService = new OrganizationService("Xrm");
var uncachedXrmServiceContext = new XrmServiceContext(uncachedOrganizationService);
var ent = uncachedXrmServiceContext.Retrieve(ConstantKVP.AccountSchema.ENTITY_LOGICAL_NAME,AccountId,new ColumnSet(true));
I am using Ms Dynamic Web Api with Simple OData. I need to add new record for link entities.
I am using the below code snip and refer the documentation on
https://github.com/object/Simple.OData.Client/wiki/Adding-entries-with-links
var newContactData = await _oDataClient
.For<Contacts>()
.Set(new
{
firstname = contactData.ContatDetails.firstname,
lastname = contactData.ContatDetails.lastname,
emailaddress1 = contactData.ContatDetails.emailaddress1
})
.InsertEntryAsync(true);
var newContactLink = await _oDataClient.For<New_project_contactses>()
.Set(new
{
_new_contact_project_name_new_value = contactData.ContatDetailsLink._new_contact_project_name_new_value,
new_project_contactsid = new Guid("0eb46b24-21a2-e611-80eb-c4346bc5b2d4"),
new_contact_type = contactData.ContatDetailsLink.new_contact_type,
})
.InsertEntryAsync(resultRequired: true);
i am getting exception
CRM do not support direct update of Entity Reference properties, Use
Navigation properties insteadS
Well, it is possible, but you need to use the special "#odata.bind" syntax to update your single-navigation properties.
For example, to update an account so that it references an existing primarycontactid, you can use a PATCH operation to the /api/data/v8.2/accounts endpoint with the following body:
{
"name":"Sample Account",
"primarycontactid#odata.bind":"/contacts(00000000-0000-0000-0000-000000000001)"
}
See https://msdn.microsoft.com/en-us/library/gg328090.aspx#Anchor_3 (it is discussed in terms of creating an entity, but it works for updating as well).
I figure out the issue With Dynamc CRM you cannot directly update reference entities Field. You can identify reference entity properties start with "_".
I am trying to import Attachments/Annotations to CRM Dynamics, I am doing this using the SDK.
I am not using the data import wizard.
I am not individually creating Annotation entities, instead I am using Data Import Feature programmatically.
I mostly leveraged the DataImport sample from the SDK sample code (SDK\SampleCode\CS\DataManagement\DataImport).
Import import = new Import()
{
ModeCode = new OptionSetValue((int)ImportModeCode.Create),
Name = "Data Import"
};
Guid importId = _serviceProxy.Create(import);
_serviceProxy.Create(
new ColumnMapping()
{
ImportMapId = new EntityReference(ImportMap.EntityLogicalName, importMapId),
ProcessCode = new OptionSetValue((int)ColumnMappingProcessCode.Process),
SourceEntityName = sourceEntityName,
SourceAttributeName = sourceAttributeName,
TargetEntityName = targetEntityName,
TargetAttributeName = targetAttributeName
});
I am getting an error "The reference to the attachment could not be found".
The documentation says the crm async service will find the physical file on disk and upload it, my question is where does the async service look for attachment files?
I tried to map documentbody field to the full path of the attachment on the desk, but that still didn't work.
The answer below was provided before the question edits clarifying the use of the import wizard instead of the SDK. The answer below is specific to using the SDK.
When you are attaching files to an Annotation (Note) record in CRM via the SDK, you do use the documentbody attribute (along with mimetype), but you have to first convert it base64.
Something like this:
var myFile = #"C:\Path\To\My\File.pdf";
// Do checks to make sure file exists...
// Convert to Base64.
var base64Data = Convert.ToBase64String(System.IO.File.ReadAllBytes(myFile));
var newNote = new Entity("annotation");
// Set subject, regarding object, etc.
// Add the data required for a file attachment.
newNote.Attributes.Add("documentbody", base64Data);
newNote.Attributes.Add("mimetype", "text/plain"); // This mime type seems to work for all file types.
orgService.Create(newNote);
I found the solution in an obscure blog post, I think the documentation is misleading or unclear, the way this whole thing works, makes having the files available on the server disk for the async to process, odd.
To follow the same principle, all contents should be sent like the csv file itself while being linked to the same import.
To solve this we need create individual special Internal ImportFile for each physical attachment, and link it to the import that has the attachments record details.
As you see below with linking the attachments ImportFile using the ImportId and then setting the two properties (ProcessCode and FileTypeCode), it all worked in the end.
Suffice to say using this method is much more efficient and quicker than individually creating Annotation records.
foreach (var line in File.ReadLines(csvFilesPath + "Attachment.csv").Skip(1))
{
var fileName = line.Split(',')[0].Replace("\"", null);
using (FileStream stream = File.OpenRead(attachmentsPath + fileName))
{
byte[] byteData = new byte[stream.Length];
stream.Read(byteData, 0, byteData.Length);
stream.Close();
string encodedAttachmentData = System.Convert.ToBase64String(byteData);
ImportFile importFileAttachment = new ImportFile()
{
Content = encodedAttachmentData,
Name = fileName,
ImportMapId = new EntityReference(ImportMap.EntityLogicalName, importMapId),
UseSystemMap = true,
ImportId = new EntityReference(Import.EntityLogicalName, importId),
ProcessCode = new OptionSetValue((int)ImportFileProcessCode.Internal),
FileTypeCode = new OptionSetValue((int)ImportFileFileTypeCode.Attachment),
RecordsOwnerId = currentUserRef
};
_serviceProxy.Create(importFileAttachment);
}
idx++;
}
I am trying to create a new contact using Dynamic Entity. The sample i found in CRM SDK had this code.
// Set the properties of the contact using property objects.
StringProperty firstname = new StringProperty();
firstname.Name = "firstname";
firstname.Value = "Jesper";
StringProperty lastname = new StringProperty();
lastname.Name = "lastname";
lastname.Value = "Aaberg";
// Create the DynamicEntity object.
DynamicEntity contactEntity = new DynamicEntity();
// Set the name of the entity type.
contactEntity.Name = EntityName.contact.ToString();
// Set the properties of the contact.
contactEntity.Properties = new Property[] {firstname, lastname};
In my code i have the following implementation.
StringProperty sp_Field1 = new StringProperty("Field1","Value1");
StringProperty sp_Field2 = new StringProperty("Field2","Value1");
CrmService service = new CrmService();
service.Credentials = System.Net.CredentialCache.DefaultCredentials;
// Create the DynamicEntity object.
DynamicEntity contactEntity = new DynamicEntity();
// Set the name of the entity type.
contactEntity.Name = EntityName.contact.ToString();
// Set the properties of the contact.
contactEntity.Properties = new Property[] {sp_Field1,sp_Field2};
I don't see much differences in the code. In the examples i found in the internet i have the same implementation as i found in SDK. But if i run the same i get the following error
CS0029: Cannot implicitly convert type 'Microsoft.Crm.Sdk.StringProperty' to 'Microsoft.Crm.Sdk.PropertyCollection'
I tried created a new variable of type PropertyCollection(one that belongs in mscrm namespace) and added the stringpropertys into that and passed it to the entity.
Microsoft.Crm.Sdk.PropertyCollection propTest = new Microsoft.Crm.Sdk.PropertyCollection();
propTest.Add(sp_SSNNo);
propTest.Add(sp_FirstName);
contactEntity.Properties = new Property[] {propTest};
This gave me the following error
CS0029: Cannot implicitly convert type 'Microsoft.Crm.Sdk.PropertyCollection' to 'Microsoft.Crm.Sdk.Property'
I am sure its a minor typecasting error but i am not able to figure out where the error is. And moreover, even if it was a typecasting error why is it working for all the samples given in the internet and not for me. I tried getting the code sample to run but i am encountering the same conversion error. Please let me know if you need more info on this, any help on this would be appreciated.
Here is an article from Microsoft that makes an attempt to discuss this topic:
http://community.dynamics.com/blogs/cscrmblog/archive/2008/06/23/web-services-amp-dlls-or-what-s-up-with-all-the-duplicate-classes.aspx
This is not a bug that you are running into but more of a difference in design between the way the two assemblies work and what they are designed to do.
If you want to continue to use the Microsoft.Crm.Sdk.dll you should be able to accomplish your goal with the following...
StringProperty sp_Field1 = new StringProperty("Field1","Value1");
StringProperty sp_Field2 = new StringProperty("Field2","Value1");
CrmService service = new CrmService();
service.Credentials = System.Net.CredentialCache.DefaultCredentials;
// Create the DynamicEntity object.
DynamicEntity contactEntity = new DynamicEntity();
// Set the name of the entity type.
contactEntity.Name = EntityName.contact.ToString();
// Set the properties of the contact.
PropertyCollection properties = new PropertyCollection();
properties.Add(sp_Field1);
contactEntity.Properties = properties;
Thanks SaaS Developer, that code is working fine now. One more way of doing it would be to directly add the StringProperty to the entity property collection.
contactEntity.Properties.Add(sp_SSNNo);
Thanks again for replying :)
I believe the issue is that you are referencing the dynamic entity class in the Microsoft.Crm.Sdk assembly. The sample in the SDK is using a reference to the CRM web service. This can get confusing as both assemblies contain many of the same types, however they are different.