for my project, I have to create multiple Quotes and add products to it.
For performance reasons (about 5000 quotes) I am using "ExecuteMultipleRequest()".
This is about what I've got:
var quote = new Quote
{
QuoteNumber = "123",
Name = "test123",
PriceLevelId = new EntityReference(PriceLevel.EntityLogicalName, Pricelevel.Id),
CustomerId = new EntityReference(Account.EntityLogicalName, Customer.Id),
};
_requests.Requests.Add(new CreateRequest { Target = quote });
var quoteDetail = new QuoteDetail
{
QuoteId = new EntityReference(Quote.EntityLogicalName, quote.Id),
ProductId = new EntityReference(Product.EntityLogicalName, product.Id),
IsPriceOverridden = true,
PricePerUnit = new Money(20),
Quantity = Convert.ToDecimal(5),
};
_requests.Requests.Add(new CreateRequest { Target = quoteDetail });
My problem is the quote.Id. I know it is empty until the server processes the request and creates the quote.
Is there a way to tell the server it should use the quotes new id for the quotedetail?
Or is my only way to create the quote itself and then create all details?
What can I do to increase performance if I have to do it this way?
Instead of sending CreateRequests explicity, you could change your code to use the OrganizationServiceContext, which locally tracks changes to objects before submitting them to CRM.
When using the OrganizationServiceContext, you can use AddRelatedObject to both add an object and link it to another one:
Adds a related entity to the OrganizationServiceContext and creates
the link that defines the relationship between the two entities in a
single request.
Alternatively you could manually call AddObject and AddLink.
You final code would look similar to the following:
using (var context = new OrganizationServiceContext(_serviceProxy))
{
var quote = new Quote
{
QuoteNumber = "123",
Name = "test123",
PriceLevelId = new EntityReference(PriceLevel.EntityLogicalName, pricelevel.Id),
CustomerId = new EntityReference(Account.EntityLogicalName, customer.Id),
};
context.AddObject(quote);
var quoteDetail = new QuoteDetail
{
ProductId = new EntityReference(Product.EntityLogicalName, product.Id),
IsPriceOverridden = true,
PricePerUnit = new Money(20),
Quantity = Convert.ToDecimal(5),
};
context.AddRelatedObject(quote, new Relationship("quote_details"), quoteDetail);
context.SaveChanges();
}
Related
I think I am on the right path, but my C# code is not creating document in Azure CosmosDB.
Below is my documentdb code:
using (var client = new DocumentClient(new Uri(endpoint), authkey))
{
Database database = client.CreateDatabaseQuery("SELECT * FROM c WHERE c.id = 'db'").AsEnumerable().First();
var query = new SqlQuerySpec
{
QueryText = "SELECT * FROM c WHERE c.id = #id",
Parameters = new Microsoft.Azure.Documents.SqlParameterCollection { new Microsoft.Azure.Documents.SqlParameter { Name = "#id", Value = collectionId }
}
};
DocumentCollection collection = client.CreateDocumentCollectionQuery(database.SelfLink,query).AsEnumerable().First();
dynamic document1Definition = new
{
name = "Admin",
address = 1,
};
var result = client.CreateDocumentAsync(collection.SelfLink, document1Definition);
}
Also want to point out, currently there are no columns named as "name" and "address" in my collection. So according to my knowledge they are suppose to be created dynamically. Please let me know what wrong are you doing?
See last statement, you are using c# Async method without await.
Use await client.CreateDocumentAsync(collection.SelfLink, document1Definition); or your code will exit before document creation is finished.
Note that your method should change to public async Task methodname(), you will see related tip shown by VS.
Some references for you
Async and Await
How and when to use async and-await
Consider the following database structure (created using EF Code First)
Using simple code as illustrated below I can easily add either new Customers or Suppliers;
private static void InsertCustomers()
{
var customer1 = new Customer
{
FirstName = "Mickey",
LastName = "Mouse",
DateStarted = DateTime.Now
};
var customer2 = new Customer
{
FirstName = "Fred",
LastName = "Flintstone",
DateStarted = DateTime.Now
};
using (var context = new ContactsContext())
{
context.Database.Log = Console.Write; //purely for logging
context.Customers.Add(customer1);
context.Customers.Add(customer2);
context.SaveChanges();
}
}
My question is simple. Fred Flintstone could at some point in the future become a supplier as well as remaining a Customer. From within SSMS I can easily achieve this but I would obviously like to do this from within the application itself. If I use the syntax
var sup = new Supplier();
then the underlying logic will create a new Id (which is perfectly sensible, but undesired as I want to use the existing Id assigned to Fred Flinstone as a Customer which is 2) so how do I in effect add an existing Contacts.Id into the Suppliers table so that it becomes a Primary / foreign key using code in my application.
Well it would transpire that this is not as intuitive in Code First as one might have thought so I have reverted to using the following which does work as intended;
static void CreateSupplier(int id)
{
var contactId = id; //the id being passed in would have been collected from a list of Customers, as we want Fred Flintstone it would have been set to 2
var date = DateTime.UtcNow;
using (var context = new ContactsContext())
{
context.Database.Log = Console.Write; //purely for logging
context.Database.ExecuteSqlCommand(
"INSERT INTO Contacts.Suppliers(Id, DateStarted) VALUES({0}, {1})", contactId, date);
context.SaveChanges();
}
}
It's possible that there is a way to do this with a lambda but at present I haven't found one.
If I have a GUID for a record, but I do not know whether it is an Account or a Contact, how can I retrieve this record and identify its type?
For example, I can retrieve a specified type like so:
var serviceAppointment = organizationService.Retrieve(
"serviceappointment",
serviceActivityGuid,
new ColumnSet(true));
However, if I do not know what type of record it is, how can I retrieve it and identify its type?
Something like this:
var myEntity = organizationService.Retrieve(
"????",
myEntityGuid,
new ColumnSet(true));
If you reference the DLaB.Xrm from Nuget, you could write this like this:
bool isAccount = service.GetEntitiesById<Account>(customerId).Count == 1;
If you wanted to actually get the actual values, you could do this.
var customerId = System.Guid.NewGuid();
var entity = service.GetEntitiesById<Account>(customerId).FirstOrDefault() ??
service.GetEntitiesById<Contact>(customerId).FirstOrDefault() as Entity;
if (entity != null)
{
var account = entity as Account; // will be null if the Guid was for a contact
var contact = entity as Contact; // will be null if the Guid was for an account
}
You cannot search by the GUID alone.
You need both the GUID and the entity logical name.
Whenever you retrieve a entity reference using code, c# or javascript, the object will include the entity logical name
Update to try to find an account with a given ID:
Guid Id = // Your GUID
IOrganizationService serviceProxy = // Create your serivce proxy
var accountQuery = new QueryExpression
{
EntityName = "account",
TopCount = 1,
Criteria =
{
Conditions =
{
new ConditionExpression("accountid", ConditionOperator.Equal, Id)
}
}
}
var response = serviceProxy.RerieveMultiple(accountQuery);
if(null == response.Entities.FirstOrDefault())
{
//No Account Record Found
}
If you only need to distinguish between with Account and Contact and want to make sure the record really still exists, you could also use their CustomerAddress, LEFT OUTER JOINing both, Account and Contact:
var query = new QueryExpression
{
EntityName = "customeraddress",
ColumnSet = new ColumnSet("customeraddressid"),
TopCount = 1,
Criteria = new FilterExpression
{
Conditions =
{
// limit to Address 1
new ConditionExpression("addressnumber", ConditionOperator.Equal, 1),
// filter by "anonymous" GUID
new ConditionExpression("parentid", ConditionOperator.Equal, myEntityGuid),
},
},
LinkEntities =
{
new LinkEntity
{
EntityAlias = "acc",
Columns = new ColumnSet("name"),
LinkFromEntityName = "customeraddress",
LinkFromAttributeName = "parentid",
LinkToAttributeName = "accountid",
LinkToEntityName = "account",
JoinOperator = JoinOperator.LeftOuter
},
new LinkEntity
{
EntityAlias = "con",
Columns = new ColumnSet("fullname"),
LinkFromEntityName = "customeraddress",
LinkFromAttributeName = "parentid",
LinkToAttributeName = "contactid",
LinkToEntityName = "contact",
JoinOperator = JoinOperator.LeftOuter
},
},
};
... will allow you to retrieve whichever, Account or Contact in one go:
var customer = service.RetrieveMultiple(query).Entities.FirstOrDefault();
... but require to access their fields through AliasedValues:
string customername = (customer.GetAttributeValue<AliasedValue>("acc.name") ?? customer.GetAttributeValue<AliasedValue>("con.fullname") ?? new AliasedValue("whatever", "whatever", null)).Value as string;
... which can make reading a lot of attributes a little messy.
I know this is an old question, but I thought I would add something in case someone stumples upon this in the future with a problem similar to mine. In this case it might not be particularly the same as OP has requested.
I had to identify whether an entity was one or the other type, so I could use one method instead of having to write standalone methods for each entity. Here goes:
var reference = new EntityReference
{
Id = Guid.NewGuid(),
LogicalName = "account" //Or some other logical name - "contact" or so.
}
And by passing it into the following method the type can be identified.
public void IdentifyType(EntityReference reference)
{
switch(reference.LogicalName)
{
case Account.EntityLogicalName:
//Do something if it's an account.
Console.WriteLine($"The entity is of type {nameof(Account.EntityLogicalName)}."
case Contact.EntityLogicalName:
//Do something if it's a contact.
Console.WriteLine($"The entity is of type {nameof(Contact.EntityLogicalName)}."
default:
//Do something if neither of above returns true.
Console.WriteLine($"The entity is not of type {nameof(Account.EntityLogicalName)} or {nameof(Contact.EntityLogicalName)}."
}
}
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);
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);