I am attempting to change the "FullName" field of existing CRM system users in our Dynamics CRM 2011 Online account. I have already made the change in settings to update all future users to the format "Last, First" ... so this is for changing the existing users.
I read the best way is to do this programmatically using the CRM SDK. When I perform the actual Update command, I receive an unspecified error from the SDK: Additional information: The property IsLicensed cannot be modified.
Although I'm querying all columns for entity object SystemUsers, I'm only changing the FullName field. Has anyone else had experience with this? My code is below, I'm running this as a console app to step through each SystemUser.
static void Main(string[] args)
{
string connStr = ConfigurationManager.ConnectionStrings["CRMOnline"].ToString();
CrmConnection conn = CrmConnection.Parse(connStr);
conn.DeviceCredentials = DeviceIdManager.LoadOrRegisterDevice();
using (OrganizationService svc = new OrganizationService(conn))
{
QueryExpression qry = new QueryExpression();
qry.ColumnSet = new ColumnSet(true); // get all columns
qry.EntityName = CRMO.SystemUser.EntityLogicalName; // get entity object SystemUser
qry.Criteria.AddCondition(new ConditionExpression("calendarid", ConditionOperator.NotNull)); // but non-builtin users
EntityCollection col = svc.RetrieveMultiple(qry); // executes query
foreach (Entity ent in col.Entities)
{
Console.WriteLine();
Console.WriteLine("Current Fullname: " + ent.Attributes["fullname"].ToString());
Console.Write("Change? y/N: ");
string ans = Console.ReadLine();
if (ans.ToLower() == "y")
{
Console.Write("New Name: ");
string newname = Console.ReadLine();
if (newname != "")
{
ent.Attributes["fullname"] = newname;
svc.Update(ent); // fails here with SDK error: "Additional information: The property IsLicensed cannot be modified."
}
}
}
Console.WriteLine();
Console.WriteLine("--- Done ---");
Console.ReadLine();
}
}
Rule 28 of the Crm SDK, don't ever perform updates by performing a select, which returns back more fields than what you are planning to update. Any fields in the attribute collection of the Entity will be updated even if they haven't changed. Instead, instantiate a new entity locally, set the id and whatever attributes you want to update and update it.
On a side note, you can't update the full name of a System User. You have to update the individual pieces. So your code should really look like this:
static void Main(string[] args)
{
string connStr = ConfigurationManager.ConnectionStrings["CRMOnline"];
CrmConnection conn = CrmConnection.Parse(connStr);
conn.DeviceCredentials = DeviceIdManager.LoadOrRegisterDevice();
using (OrganizationService svc = new OrganizationService(conn))
{
QueryExpression qry = new QueryExpression();
qry.ColumnSet = new ColumnSet("firstname", "lastname", "fullname"); // get only what is needed for performance reasons
qry.EntityName = CRMO.SystemUser.EntityLogicalName; // get entity object SystemUser
qry.Criteria.AddCondition(new ConditionExpression("calendarid", ConditionOperator.NotNull)); // but non-builtin users
EntityCollection col = svc.RetrieveMultiple(qry); // executes query
foreach (Entity ent in col.Entities)
{
Console.WriteLine();
Console.WriteLine("Current Fullname: " + ent["fullname"].ToString());
Console.Write("Update? Y/N: ");
string ans = Console.ReadLine();
if (ans.ToLower() == "y")
{
// Create a new entity, setting the id and whatever attributes that need to be updated
var updateEntity = new Entity { Id = ent.Id };
updateEntity["firstname"] = ent["firstname"];
updateEntity["lastname"] = ent["lastname"];
svc.Update(updateEntity);
}
}
Console.WriteLine();
Console.WriteLine("--- Done ---");
Console.ReadLine();
}
}
Notes:
Only retrieve the columns you actually need
Create an update entity that only contains the fields you want to update
Remember that FullName is readonly
This may also be helpful
This is so others reading this can use this solution to change the FullName in CRM Online.
So in my case, where I needed to change the FullName of existing CRM users from "First Last" to "Last, First", I was able to perform regular Office 365 admin functions to complete this.
First, I changed the format in CRM Settings > System Settings to "Last Name, First Name".
Then, for each user I needed to have changed, I used the Office 365 Admin Center and edited their licenses. Un-assign the CRM license from the user and click SAVE. Wait about a minute or two for the changes to take affect. Next, go back into that same user management and re-assign the CRM license to the user, click SAVE. Wait a few minutes and you will see the FullName in CRM should be in the correct format.
Related
I'm using MongoDB 4.0.8 with C# driver 2.8.1 and I'm trying to implement Transactions in my project.
I copy-pasted the following code sample:
static async Task<bool> UpdateProducts()
{
//Create client connection to our MongoDB database
var client = new MongoClient(MongoDBConnectionString);
//Create a session object that is used when leveraging transactions
var session = client.StartSession();
//Create the collection object that represents the "products" collection
var products = session.Client.GetDatabase("MongoDBStore").GetCollection<Product>("products");
//Clean up the collection if there is data in there
products.Database.DropCollection("products");
//Create some sample data
var TV = new Product { Description = "Television", SKU = 4001, Price = 2000 };
var Book = new Product { Description = "A funny book", SKU = 43221, Price = 19.99 };
var DogBowl = new Product { Description = "Bowl for Fido", SKU = 123, Price = 40.00 };
//Begin transaction
session.StartTransaction(new TransactionOptions(
readConcern: ReadConcern.Snapshot,
writeConcern: WriteConcern.WMajority));
try
{
//Insert the sample data
await products.InsertOneAsync(session, TV);
await products.InsertOneAsync(session, Book);
await products.InsertOneAsync(session, DogBowl);
var filter = new FilterDefinitionBuilder<Product>().Empty;
var results = await products.Find(filter).ToListAsync();
//Increase all the prices by 10% for all products
var update = new UpdateDefinitionBuilder<Product>().Mul<Double>(r => r.Price, 1.1);
await products.UpdateManyAsync(session, filter, update); //,options);
//Made it here without error? Let's commit the transaction
session.CommitTransaction();
//Let's print the new results to the console
Console.WriteLine("Original Prices:\n");
results = await products.Find<Product>(filter).ToListAsync();
foreach (Product d in results)
{
Console.WriteLine(String.Format("Product Name: {0}\tPrice: {1:0.00}", d.Description, d.Price));
}
}
catch (Exception e)
{
Console.WriteLine("Error writing to MongoDB: " + e.Message);
session.AbortTransaction();
}
return true;
}
But in the first Insert command, I'm getting this error:
Command insert failed:
Transaction numbers are only allowed on a replica set member or mongos.
The Documentation says that:
Starting in version 4.0, MongoDB provides the ability to perform multi-document transactions against replica sets.
I don't have replicas in my project, I have only one database instance which is my primary one. If there a solution or a work-around I can use to implement Transactions? I have methods that update more than one collection and I really think it could save me time to use it.
like the documentation says, transactions only work with replica sets. so you need to run your mongodb server as single node replica set. to achieve that, do the following steps...
step 1:
stop the mongodb server.
step 2:
add the replication setting to your mongod.cfg file. here's my own as an example
storage:
dbPath: C:\DATA
directoryPerDB: true
journal:
enabled: true
systemLog:
destination: file
logAppend: true
path: C:\DATA\log\mongod.log
net:
port: 27017
bindIp: 127.0.0.1
replication:
replSetName: MyRepSet
step 3: open up a mongodb shell and issue the following command to initiate the replica set.
rs.initiate()
step 4: restart mongod
on a side-note, if you'd like to write cleaner, more convenient transaction code like the following, check out my library MongoDB.Entities
using (var TN = new Transaction())
{
var author = new Author { Name = "one" };
TN.Save(author);
TN.Delete<Book>(book.ID);
TN.Commit();
}
I'm writing an ASP.NET app that should connect to dynamics CRM and fetch the contacts info. In the view it should return a list of the contacts with their info. There is some data in the testing CRM I'm provided with but I can't get the entities (e.g. table name and its columns), so I can't create my models in VS, since I don't know what props to put there.
Is there a way to get the entites with the code, or how can this problem be solved?
I've tried early-bound generator, and it won't work. I tried with ADO.NET entity data model but doesn't work either.
In order to actually work with the CRM entities you're going to need to configure your project to work with an Organization Service (Might need a different tutorial depending on CRM version) that connects to your CRM instance.
Afterwards, like David Yenglin was explaining, you should be able to use methods like IOrganizationService.Retrieve(String, Guid, ColumnSet) which allows you to retrieve a record or IOrganizationService.RetrieveMultiple(QueryBase) which allows you to retrieve multiple records. In your case, I think you just need the Retrieve method.
Another way you can access the data is through the CRM Web API (which I have less experience with) which would allow you to query the data from CRM.
There's a ton of great examples of different scenarios over at Microsoft's github repo, PowerApps-Samples. I'd recommend checking it out later when you get your project configured.
This article will give you step by step way to connect to CRM.
Once you get sucessfully connected to CRM, try below code which will give you complete information about all the contact Records.
try
{
ClientCredentials clientCredentials = new ClientCredentials();
clientCredentials.UserName.UserName = "<ProvideUserName>#<ProvideYourOrgName>.onmicrosoft.com";
clientCredentials.UserName.Password = "<ProvideYourPassword>";
// For Dynamics 365 Customer Engagement V9.X, set Security Protocol as TLS12
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
// Get the URL from CRM, Navigate to Settings -> Customizations -> Developer Resources
// Copy and Paste Organization Service Endpoint Address URL
organizationService = (IOrganizationService)new OrganizationServiceProxy(new Uri("https://<ProvideYourOrgName>.api.<CRMRegion>.dynamics.com/XRMServices/2011/Organization.svc"),
null, clientCredentials, null);
if (organizationService != null)
{
Guid userid = ((WhoAmIResponse)organizationService.Execute(new WhoAmIRequest())).UserId;
if (userid != Guid.Empty)
{
Console.WriteLine("Connection Established Successfully...");
// your logic here.
queryExpressionTest(organizationService);
}
}
else
{
Console.WriteLine("Failed to Established Connection!!!");
}
}
catch (Exception ex)
{
Console.WriteLine("Exception caught - " + ex.Message);
}
Console.ReadKey();
}
private static void queryExpressionTest(IOrganizationService organizationService)
{
QueryExpression qe = new QueryExpression();
qe.EntityName = "contact";
qe.ColumnSet= new ColumnSet(true); // this will give you all the columns of contact record
//qe.ColumnSet= new ColumnSet("name", "accountnumber"); you could also restrict which particualr attributes you wish to retrieve from contact record.
EntityCollection coll = organizationService.RetrieveMultiple(qe);
foreach (Entity cont in coll.Entities)
{
Console.WriteLine("Name of contact: " + cont.GetAttributeValue<string>("fullname"));
Console.WriteLine("Email of contact " + cont.GetAttributeValue<string>("email"));
/**
Now you can add all the attributes you wish to show
*/
}
}
Hello I have a console application in which I hard codedly add records. Afterwards I make manual modifications and additions, showing them on the console aswell. The modifications and additions are seen on the console but the actual modification not, while the ones that were added are seen in their new state.
I.E.:
Record 1: "John" modified to "K"
Console application shows that Record 1 has been modified but the name property doesn't show the actual property it shows the old one.
While when I add Record 2 the console shows the actual data of the new record. Why is this?
Console.WriteLine("Welcome. Type YES to hard codedly add records.)");
if (Console.ReadLine().Equals("YES"))
{
using (var db = new HomeContext())
{
db.Homes.Add(new Home { Owner = "John", Time = DateTime.Now });
var count = db.SaveChanges();
DateTime old = db.Homes.Max(u => u.Time);
Console.WriteLine("{0} records saved to database", count);
Console.WriteLine("All records:");
foreach (var home in db.Homes)
{
Console.WriteLine(home);
}
Console.WriteLine("When you've made the manual changes through SQL Explorer GUI on Visual Studio, type YES");
if (Console.ReadLine().Equals("YES"))
{
var records = db.Homes.Where(u => u.Time > old).ToList();
Console.WriteLine("These are the recently made changes:");
foreach (var home in records)
{
Console.WriteLine(home);
}
}
Console.ReadKey();
}
}
CONSOLE OUTPUT:
ALL RECORDS:
Home 1 Owner John
adding modifying manually using Explorer
Typing YES
These are the recently made changes:
Home 1 Owner John
Home 2 Owner newRecord
Change the structure little bit.
While querying the database use new object of DB context
Im trying to create a plugin for CRM that queries a mysql db and pulls the data from the db and adds it to a field in crm. What i have so far is this below, but im not sure how to assign a table column to a field value in crm?
`namespace Microsoft.Crm.Sdk.Samples
{
public class AssignSMSPlugin: IPlugin
{
/// <summary>
/// A plug-in that creates a follow-up task activity when a new account is created.
/// </summary>
/// <remarks>Register this plug-in on the Create message, account entity,
/// and asynchronous mode.
/// </remarks>
public void Execute(IServiceProvider serviceProvider)
{
//Conect to mySQl Database
String str ="";
MySqlConnection con = null;
MySqlDataReader reader = null;
try
{
con = new MySqlConnection(str);
con.Open();
//Select statement to query table to get certain columns
string cmdText = "SELECT col1, col2, col3 FROM table1";
MySqlCommand cmd = new MySqlCommand(cmdText, con);
reader = cmd.ExecuteReader();
// while (reader.Read())
// {
// Console.WriteLine(reader.GetString(0));
// }
//Extract the tracing service for use in debugging sandboxed plug-ins.
ITracingService tracingService =
(ITracingService)serviceProvider.GetService(typeof(ITracingService));
// Obtain the execution context from the service provider.
IPluginExecutionContext context = (IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));
// The InputParameters collection contains all the data passed in the message request.
if (context.InputParameters.Contains("Target") &&
context.InputParameters["Target"] is Entity)
{
// Obtain the target entity from the input parameters.
Entity entity = (Entity)context.InputParameters["Target"];
// Verify that the target entity represents an account.
// If not, this plug-in was not registered correctly.
if (entity.LogicalName != "customer")
return;
try
{
// Create a sms activity.Assign table column to field in crm
Entity assign = new Entity("SMS Message");
assign["to"] = "";
assign["subject"] = "";
assign["contact"] = ;
assign["regardingobjectid"] = ;
// Refer to the account in the task activity.
if (context.OutputParameters.Contains("id"))
{
Guid regardingobjectid = new Guid(context.OutputParameters["id"].ToString());
string regardingobjectidType = "customer";
assign["regardingobjectid"] =
new EntityReference(regardingobjectidType, regardingobjectid);
}
// Obtain the organization service reference.
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
// Create the task in Microsoft Dynamics CRM.
tracingService.Trace("AssignSMSPlugin: Creating the SMS Activity.");
service.Create(assign);
}
catch (FaultException<OrganizationServiceFault> ex)
{
throw new InvalidPluginExecutionException("An error occurred in the AssignSMSPlugin plug-in.", ex);
}
catch (Exception ex)
{
tracingService.Trace("AssignSMSPlugin: {0}", ex.ToString());
throw;
}
}
}
}`
Your logic looks faulty to me.
1) Change the part here
assign["to"] = "";
assign["subject"] = "";
assign["contact"] = ;
assign["regardingobjectid"] = ;
you need to actually assign values instead of nulls/empty strings.
2) There is generally some type of primary field (usually name/subject/title) on any entity; that should be set (I assume that is the subject field, which is currently = "") or it will come back to bite you.
3) you probably should use Entity.Attributes.Contains("id") instead of "OutputParameters" for context.OutputParameters.Contains("id") as I doubt you registered the plugin to have output parameters (this would require you to be generating them from a separate plugin)
4) I don't know about accessing MySQL via C#, but I assume you need to get the data from MySQL from that "reader", and use that to populate the CRM Values.
5) in most CRM plugins, the Org Service and ServiceFactory are instantiated at the beginning along with the tracing, so I would recommend moving that up much higher (this one is more of improved readability, so you can skip it).
6) your comments keep referring to accounts, but the check at the beginning is for "customer" (again, optional as it is just poor commenting)
7) the assign "Entity" is not a valid entity name, there should not be any spaces - more likely the entity name is something like
var assign = new Entity("new_smsmessage")
I am using linq to sql in a windows form application. there is a bug that I couldn't find the solution until now!
partial void OnAmountChanging(int? value)
{
OrderLog lg = new OrderLog()
{
Date = DateTime.Now,
IPAddress = System.Net.Dns.GetHostAddresses(Environment.MachineName)[0].ToString(),
NewData = value,
OldData = this.Amount,
Status = "Changed",
User = User.CurUser,
Order = this // each Order has one-to-many relation to OrderLog entity.
};
}
this is run as soon as the value of AMOUNT changes in datagridview.
after closing the form I try to save the created log to Database:
db.SubmitChanges();
then I face this error :
An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext. This is not supported
is there any solution?