I found this snippet that provides a creation of a new entity called annotation.
I can't find the class XrmServicesContext declared into the using directive.
has anybody knows what the hell is this?
private static void AddNoteToContact(IOrganizationService service, Guid id)
{
Entity annotation = new Entity();
annotation.LogicalName = "annotation";
using (var crm = new XrmServicesContext(service))
{
var contact = crm.ContactSet.Where(c => c.ContactId == id).First();
Debug.Write(contact.FirstName);
annotation["createdby"] = new EntityReference("systemuser", new Guid("2a213502-db00-e111-b263-001ec928e97f"));
annotation["objectid"] = contact.ToEntityReference();
annotation["subject"] = "Creato con il plu-in";
annotation["notetext"] = "Questa note è stata creata con l'esempio del plug-in";
annotation["ObjectTypeCode"] = contact.LogicalName;
try
{
Guid annotationId = service.Create(annotation);
crm.AddObject(annotation);
crm.SaveChanges();
}
catch (Exception e)
{
throw new Exception(e.Message);
}
// var note = new Annotation{
//Subject ="Creato con il plu-in",
//NoteText ="Questa note è stata creata con l'esempio del plug-in",
//ObjectId = contact.ToEntityReference(),
//ObjectTypeCode = contact.LogicalName
};
}
First you have to generate the early bound entity classes. Check this article. Then, insert using statement in your code.
In your example you are using combination of early and late binding. I suggest you to choose one of them. In case of early binding, after generating early binding classes you can modify your code like:
Annotation annotation = new Annotation();
using (var crm = new XrmServiceContext(service))
{
annotation.ObjectId = contact.ToEntityReference();
annotation.Subject = "Creato con il plu-in";
annotation.NoteText = "Questa note e stata creata con l'esempio del plug-in";
annotation.ObjectTypeCode = Contact.LogicalName;
crm.AddObject(annotation);
crm.SaveChanges();
}
You have one error here, annotation.CreatedBy field is read only and you can't set value to this from code.
If you're gonna use late binding, XrmServiceContext is not necessary. You can get Contact from CRM using QueryExpression. Find examples here. And for annotation create use:
Guid annotationId = service.Create(annotation);
In SDK/bin/CrmSvcUtil.exe, This tool is used to generate early bound entity classes
from command prompt, run CrmSvcUtil.exe with parameters i.e.
If your sdk bin location is "D:\Data\sdk2013\SDK\Bin\CrmSvcUtil.exe" then your command will like this,
cmd:
D:\Data\sdk 2013\SDK\Bin>CrmSvcUtil.exe /out:Xrm\Xrm.cs /url:[OrganizationServiceUrl] /username:[yourusername] /password:[yourpass] /namespace:Xrm /serviceContextName:XrmServiceContext
[OrganizationServiceUrl]: is your organization service url, u can find it from setting/customization/Developer rosources/Organization service e.g
https://msdtraders.api.crm.dynamics.com/XRMServices/2011/Organization.svc
[yourusername]: your user name
[yourpass]: your password
This will generate and Entity classes in file with name Xrm.cs in bin/Xrm/Xrm.cs. Create folder Xrm in bin if it not exist, or edit parameters in cmd [out:Xrm\Xrm.cs].
Add Xrm.cs in your project
Add using statement in your code where you use XrmServicesContext.
like using Xrm;
Now you can use/access XrmServicesContext and all Entities ...... enjoy.
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.
My specific problem is how can I automate "add-migration" in a build process for the Entity Framework. In researching this, it seems the mostly likely approach is something along the lines of automating these steps
Open a solution in Visual Studio 2013
Execute "Add-Migration blahblah" in the Package Manager Console (most likely via an add-in vsextention)
Close the solution
This initial approach is based on my own research and this question, the powershell script ultimately behind Add-Migration requires quite a bit of set-up to run. Visual Studio performs that setup automatically when creating the Package Manager Console and making the DTE object available. I would prefer not to attempt to duplicate that setup outside of Visual Studio.
One possible path to a solution is this unanswered stack overflow question
In researching the NuGet API, it does not appear to have a "send this text and it will be run like it was typed in the console". I am not clear on the lines between Visual Studio vs NuGet so I am not sure this is something that would be there.
I am able to find the "Pacakage Manager Console" ironically enough via "$dte.Windows" command in the Package Manager Console but in a VS 2013 window, that collection gives me objects which are "Microsoft.VisualStudio.Platform.WindowManagement.DTE.WindowBase". If there is a way stuff text into it, I think I need to get it to be a NuGetConsole.Implementation.PowerConsoleToolWindow" through reviewing the source code I am not clear how the text would stuffed but I am not at all familiar with what I am seeing.
Worst case, I will fall back to trying to stuff keys to it along the lines of this question but would prefer not to since that will substantially complicate the automation surrounding the build process.
All of that being said,
Is it possible to stream commands via code to the Package Manager Console in Visual Studio which is fully initialized and able to support an Entity Framework "add-migration" command?
Thanks for any suggestions, advice, help, non-abuse in advance,
John
The approach that worked for me was to trace into the entity framework code starting in with the AddMigrationCommand.cs in the EntityFramework.Powershell project and find the hooks into the EntityFramework project and then make those hooks work so there is no Powershell dependency.
You can get something like...
public static void RunIt(EnvDTE.Project project, Type dbContext, Assembly migrationAssembly, string migrationDirectory,
string migrationsNamespace, string contextKey, string migrationName)
{
DbMigrationsConfiguration migrationsConfiguration = new DbMigrationsConfiguration();
migrationsConfiguration.AutomaticMigrationDataLossAllowed = false;
migrationsConfiguration.AutomaticMigrationsEnabled = false;
migrationsConfiguration.CodeGenerator = new CSharpMigrationCodeGenerator(); //same as default
migrationsConfiguration.ContextType = dbContext; //data
migrationsConfiguration.ContextKey = contextKey;
migrationsConfiguration.MigrationsAssembly = migrationAssembly;
migrationsConfiguration.MigrationsDirectory = migrationDirectory;
migrationsConfiguration.MigrationsNamespace = migrationsNamespace;
System.Data.Entity.Infrastructure.DbConnectionInfo dbi = new System.Data.Entity.Infrastructure.DbConnectionInfo("DataContext");
migrationsConfiguration.TargetDatabase = dbi;
MigrationScaffolder ms = new MigrationScaffolder(migrationsConfiguration);
ScaffoldedMigration sf = ms.Scaffold(migrationName, false);
}
You can use this question to get to the dte object and from there to find the project object to pass into the call.
This is an update to John's answer whom I have to thank for the "hard part", but here is a complete example which creates a migration and adds that migration to the supplied project (project must be built before) the same way as Add-Migration InitialBase -IgnoreChanges would:
public void ScaffoldedMigration(EnvDTE.Project project)
{
var migrationsNamespace = project.Properties.Cast<Property>()
.First(p => p.Name == "RootNamespace").Value.ToString() + ".Migrations";
var assemblyName = project.Properties.Cast<Property>()
.First(p => p.Name == "AssemblyName").Value.ToString();
var rootPath = Path.GetDirectoryName(project.FullName);
var assemblyPath = Path.Combine(rootPath, "bin", assemblyName + ".dll");
var migrationAssembly = Assembly.Load(File.ReadAllBytes(assemblyPath));
Type dbContext = null;
foreach(var type in migrationAssembly.GetTypes())
{
if(type.IsSubclassOf(typeof(DbContext)))
{
dbContext = type;
break;
}
}
var migrationsConfiguration = new DbMigrationsConfiguration()
{
AutomaticMigrationDataLossAllowed = false,
AutomaticMigrationsEnabled = false,
CodeGenerator = new CSharpMigrationCodeGenerator(),
ContextType = dbContext,
ContextKey = migrationsNamespace + ".Configuration",
MigrationsAssembly = migrationAssembly,
MigrationsDirectory = "Migrations",
MigrationsNamespace = migrationsNamespace
};
var dbi = new System.Data.Entity.Infrastructure
.DbConnectionInfo("ConnectionString", "System.Data.SqlClient");
migrationsConfiguration.TargetDatabase = dbi;
var scaffolder = new MigrationScaffolder(migrationsConfiguration);
ScaffoldedMigration migration = scaffolder.Scaffold("InitialBase", true);
var migrationFile = Path.Combine(rootPath, migration.Directory,
migration.MigrationId + ".cs");
File.WriteAllText(migrationFile, migration.UserCode);
var migrationItem = project.ProjectItems.AddFromFile(migrationFile);
var designerFile = Path.Combine(rootPath, migration.Directory,
migration.MigrationId + ".Designer.cs");
File.WriteAllText(designerFile, migration.DesignerCode);
var designerItem = project.ProjectItems.AddFromFile(migrationFile);
foreach(Property prop in designerItem.Properties)
{
if (prop.Name == "DependentUpon")
prop.Value = Path.GetFileName(migrationFile);
}
var resxFile = Path.Combine(rootPath, migration.Directory,
migration.MigrationId + ".resx");
using (ResXResourceWriter resx = new ResXResourceWriter(resxFile))
{
foreach (var kvp in migration.Resources)
resx.AddResource(kvp.Key, kvp.Value);
}
var resxItem = project.ProjectItems.AddFromFile(resxFile);
foreach (Property prop in resxItem.Properties)
{
if (prop.Name == "DependentUpon")
prop.Value = Path.GetFileName(migrationFile);
}
}
I execute this in my project template's IWizard implementation where I run a migration with IgnoreChanges, because of shared entites with the base project. Change scaffolder.Scaffold("InitialBase", true) to scaffolder.Scaffold("InitialBase", false) if you want to include the changes.
I notice the the CRM moderator David Jennaway on the technet forum states that you can't use LINQ to update/Create records in CRM 2011 see here http://social.microsoft.com/Forums/en-IE/crmdevelopment/thread/682a7be2-1c07-497e-8f58-cea55c298062
But I have seen a few threads that make it seem as if it should work. Here is my attempt which doesn't work. Any ideas why not?
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
OrganizationServiceContext orgContext = new OrganizationServiceContext(service);
EntityState state = new EntityState();
state = EntityState.Changed;
var counter = from c in orgContext.CreateQuery<pcx_entitycounter>()
where c.pcx_name.Contains("pcx_candidate")
select new pcx_entitycounter
{Id = c.Id,
pcx_name = c.pcx_name, pcx_Sequence = c.pcx_Sequence, pcx_Prefix = c.pcx_Prefix
};
foreach (var c in counter)
{
string prefix = c.pcx_Prefix.ToString(); ;
string sequence = c.pcx_Sequence.ToString();
c.pcx_Sequence = c.pcx_Sequence + 1;
c.EntityState = state;
**service.Update(c);** //FAILS HERE
}
In my experience, it's been difficult-to-impossible to retrieve an entity from the Context, update it, then use the Service to save the changes. It has caused me headaches figuring it out!
Since your retrieval code uses a query from the Context, all of those entities should be attached to the Context and their states are being tracked. Thus you need to use the Context's method for updating:
foreach (var c in counter) {
string prefix = c.pcx_Prefix.ToString(); ;
string sequence = c.pcx_Sequence.ToString();
c.pcx_Sequence = c.pcx_Sequence + 1;
// Use the Context to save changes
orgContext.UpdateObject(c);
orgContext.SaveChanges();
}
Since a lot of my code will retrieve entities in different ways (i.e. Service or Context) depending on the situation, I have developed a simple method that knows how to update the entity correctly. To expand on your example, you might have an update method that looks like:
public void UpdatePcxEntityCounter(pcx_entitycounter c) {
if (!orgContext.IsAttached(c)) {
service.Update(c);
}
else {
orgContext.UpdateObject(c);
orgContext.SaveChanges();
}
}
This assumes both orgContext and service are available at a scope above that of the method. Otherwise, they'd have to be passed as additional parameters.
Without seeing the difficult its difficult to discern what the issue is but have you tried using orgContext.UpdateObject(c); before doing the update step? Also, not sure why you are assigning the prefix and sequence to local variables within your loop since they don't appear to be being used. Its possible that you are getting a SOAP Exception or something for assigning values that don't work. Do you have any plugins registered on the entity?
See the following links for possible resolutions -
How to update a CRM 2011 Entity using LINQ in a Plugin?
http://social.microsoft.com/Forums/en-US/crmdevelopment/thread/7ae89b3b-6eca-4876-9513-042739fa432a
I need to generate BPEL XML code in runtime. The only way I can do it now is to create XML document with "bare hands" using DOM API. But there must be a framework that could ease such work incorporating some kind of object model.
I guess it should look something like this:
BPELProcessFactory.CreateProcess().addSequence
Do you know any?
The Eclipse BPEL designer project provides an EMF model for BPEL 2.0. The generated code can be used to programmatically create BPEL code with a convenient API.
In case anyone stumbles upon this.
Yes this can be done using the BPEL Model.
Here is a sample piece of code which generates a quite trivial BPEL file:
public Process createBPEL()
{
Process process = null;
BPELFactory factory = BPELFactory.eINSTANCE;
try
{
ResourceSet rSet = new ResourceSetImpl();
rSet.getResourceFactoryRegistry().getExtensionToFactoryMap()
.put("bpel", new BPELResourceFactoryImpl());
File file = new File("myfile.bpel");
file.createNewFile();
String filePath = file.getAbsolutePath();
System.out.println(filePath);
AdapterRegistry.INSTANCE.registerAdapterFactory( BPELPackage.eINSTANCE, BasicBPELAdapterFactory.INSTANCE );
Resource resource = rSet.createResource(URI.createFileURI(filePath));
process = factory.createProcess();
process.setName("FirstBPEL");
Sequence seq = factory.createSequence();
seq.setName("MainSequence");
Receive recieve = factory.createReceive();
PortType portType = new PortTypeProxy(URI.createURI("http://baseuri"), new QName("qname"));
Operation operation = new OperationProxy(URI.createURI("http://localhost"), portType , "operation_name");
recieve.setOperation(operation);
Invoke invoke = factory.createInvoke();
invoke.setOperation(operation);
While whiles = factory.createWhile();
If if_st = factory.createIf();
List<Activity> activs = new ArrayList<Activity>();
activs.add(recieve);
activs.add(invoke);
activs.add(if_st);
activs.add(whiles);
seq.getActivities().addAll(activs);
process.setActivity(seq);
resource.getContents().add(process);
Map<String,String> map = new HashMap<String, String>();
map.put("bpel", "http://docs.oasis-open.org/wsbpel/2.0/process/executable");
map.put("xsd", "http://www.w3.org/2001/XMLSchema");
resource.save(map);
}
catch(Exception e)
{
e.printStackTrace();
}
return process;
}
The dependencies require that you add the following jars to the project's build path from the plugins folder in eclipse installation directory:
org.eclipse.bpel.model_*.jar
org.eclipse.wst.wsdl_*.jar
org.eclipse.emf.common_*.jar
org.eclipse.emf.ecore_*.jar
org.eclipse.emf.ecore.xmi_*.jar
javax.wsdl_*.jar
org.apache.xerces_*.jar
org.eclipse.bpel.common.model_*.jar
org.eclipse.xsd_*.jar
org.eclipse.core.resources_*.jar
org.eclipse.osgi_*.jar
org.eclipse.core.runtime_*.jar
org.eclipse.equinox.common_*.jar
org.eclipse.core.jobs_*.jar
org.eclipse.core.runtime.compatibility_*.jar
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.