Retrieving an entity from CRM 4.0 - plugins

Whenever there is an update in any entity on CRM , only the updated fields of that entity are passed to corresponding plugin in addition to its ID. i want to retrieve the entity with all the fields from CRM. It turns out that I can do that by using the following code
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
so when i retrieve the entity as follows
service.Retrieve(entity.LogicalName, entity.Id, cols);
it returns data type "Entity". How can I change it to lets say contact or account.
if I use some thing like this
service.Retrieve(entity.LogicalName, entity.Id, cols).ToEntity<contact>()
...it does not recognize contact.
Any ideas??

Use the following to read data from the entity:
Entity e = service.Retrieve(entity.LogicalName, entity.Id, cols);
var x = e['attribute_to_read'];
You will have to type cast the data.

Related

Pass parameter to virtual entity data provider plugin

I'm aiming to show virtual entity records on a subgrid on the form of a custom entity (say, Client). I have created a virtual entity, custom data provider and registered the required plugin. So far things work fine; I load the form, subgrid loads with the data from external webservice.
Now, I want to pass a string field on the form (say, Client.ExternalId) as a parameter to the retrieveMultiple plugin so that I can use this field to query the datasource.
The retriveMultiple plugin steps (registered automatically when custom data provider was set up) show that it was registered on the virtual entity and not Client entity. Since it gets executed on load of the subgrid on the Client entity form I am not sure how I can pass a field to the plugin.
Can someone please give some guidance on how to achieve this?
Version 1710 (9.2.22103.194) online
Thanks
If the virtual entity has an N:1 relationship with the main entity and the subgrid is configured to show related records, then you can do like this:
// first, get the whole query
var query = context.InputParameterOrDefault<QueryExpression>("Query");
// next, get the linkEntity and then the linkFilter
var linkFilter = query.LinkEntities.FirstOrDefault(x => x.LinkToEntityName == "mainEntityLogicalName").LinkCriteria;
// next, get the main entity id
var mainEntityId = linkFilter.Conditions.FirstOrDefault(x => x.AttributeName == "mainEntityIdFieldName").Values.FirstOrDefault() as Guid?;
// finally, retreive main entity to get the Client.ExternalId
var mainEntity = orgSvc.Retrieve("mainEntityLogicalName", mainEntityId.Value, new ColumnSet("Client.ExternalId"));
var clientExternalId = mainEntity.GetAttributeValue<string>("Client.ExternalId");

CRM 2013 - Plugin to retrieve username

I have an AutoNumber plug-in that invokes when the user presses save, but I've received a requirement to append the initials of the person creating the record to the end of the ticket.
For example: 0001-0327-RBS
I have been able to get the GUID of the user creating the record, but I have no idea how to get the literal value outside of SQL. I haven't been able to figure out how I can get the user name of the active user creating the record. Is this possible from within a plug-in?
any help is appreciated. thanks.
You should get IOrganizationService from IServiceProvider
var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
var serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
var service = serviceFactory.CreateOrganizationService(context.UserId);
now you can simply retrieve the SystemUser using the service:
var systemUser = service.Retrieve("systemuser", context.UserId, new Microsoft.Xrm.Sdk.Query.ColumnSet(true));
in ColumnSet you can specify the columns which you want to retrieve (so for example "firstname", "lastname", "fullname" etc.).
Now you can simply do
systemUser["fullname"]
to get the name. Or if you are using early binds:
systemUser.ToEntity<SystemUser>().FullName

How can the Entity type of a PartyId be determined?

Using Dynamics CRM 2011. I am learning about ActivityPartys.
Since the PartyId of an ActivityParty is an EntityReference, in order to set the PartyId, you need to know the Entity type.
I am trying to create a new PhoneCall (in a plugin) using the same Recipient as an existing phone call. I can retrieve the recipient's PartyId Guid using LINQ from the ActivityPartySet, but how can I determine the Entity Type, which could be either Account or Contact?
Conversely, is it possible to set the PartyId without knowing the EntityLogicalName?
Update:
Thanks for responding but I either misunderstood you or you misunderstood what I am trying to ascertain. Here's my code right now:
// Get the oldPhoneCall's To ActivityParty list:
EntityCollection Recipients = oldPhonecall.GetAttributeValue<EntityCollection>("to");
// Use the first one to find the partyId
// Need to do it this way because we don't know if partyId points to an Account or a Contact:
Guid activityPartyId = Recipients.Entities[0].Id;
var activityParty2 = new Xrm.ActivityParty();
context.GetWorkflowHelper().serviceContext.ClearChanges();
var queryParty = from ap in context.GetWorkflowHelper().serviceContext.ActivityPartySet
where ap.ActivityPartyId.Equals(activityPartyId)
select new { ap.PartyId, ap.LogicalName };
foreach (var party in queryParty)
{
activityParty2.PartyId = new EntityReference(party.LogicalName, party.PartyId.Id);
}
I found that in the foreach, party.LogicalName is ActivityParty. This is not the entity type of oldphonecall's recipient, which in my test case is Contact but in other cases is Account.
How do I determine that entity logical name? Where have I gone wrong?
Update2:
In SQL I can see field PartyObjectTypeCode and I know I can map that to an entity type (where 1 = Account, 2= Contact, etc.) but when I query the ActivityPartySet, no such field seems to exist.
Update 3:
Got it -
foreach (var party in queryParty)
{
activityParty2.PartyId = new EntityReference(party.PartyId.LogicalName, party.PartyId.Id);
}
how can I determine the Entity Type, which could be either Account or
Contact?
PartyId is of the type EntityReference where LogicalName would give you the related entity type.
var entityLogicalName = context.EmailSet.FirstOrDefault().To.FirstOrDefault().PartyId.LogicalName
Conversely, is it possible to set the PartyId without knowing the
EntityLogicalName?
No, when setting a CRM entity reference both Id and LogicalName are required fields.
In order to set the PartyId you need to know the LogicalName of the entity.
You didn't post the code, but if you are able to retrieve the Id from a recipient you can retrieve also the LogicalName (they are stored as EntityReference)

Attaching an related entity to new entity, without retrieving from database

I've just started working with Web API this week, and I'm struggling with something which I think should be quite simple, but haven't been able to find the answer for yet. Perhaps I'm searching using the wrong terms.
One of the calls to the API passes through a GUID. I need to create a new entity (using Entity Framework) and set one of the relations to this newly passed in GUID. This GUID is the ID of a different entity in the database.
I'm struggling to attach the entity via the relation without fetching the whole entity too.
For example,
public void DoWork(IList<Guid> userGuids)
{
Order order = new Order() // This is an entity
{
CreateDate = DateTime.Now,
CreatedBy = "Me",
Items = (from i in this.Model.Items
where i.Id == userGuid
select i).ToList<Item>();
}
Model.Orders.Add(order);
Model.SaveAll();
}
In the above, I have to do a database call to attach the Item entities to the Order. Is there not a way around this? Seems very redundant to retrieve the whole entity objects when I only require their IDs (which I already have anyway!)!
One solution is stub entities as asked here: Create new EF object with foreign key reference without loading whole rereference object
Link to the source blog referenced: http://blogs.msdn.com/b/alexj/archive/2009/06/19/tip-26-how-to-avoid-database-queries-using-stub-entities.aspx
Snip from the blog - to be applied to your situation:
Category category = new Category { ID = 5};
ctx.AttachTo(“Categories”,category);
Product product = new Product {
Name = “Bovril”,
Category = category
};
ctx.AddToProducts(product);
ctx.SaveChanges();
This way (in the example) the Product is saved without ever loading the Category object.

Using the entity framework to add existing entities to a collection on a newly created entity

I am using the Entity framework to create a new order. The order contains a collection of contacts, a many to many relationship. I want to add a reference to an existing contact on the order on creation of the order. Both Order and Contact a Entity Objects.
Order order = new Order();
//set details on order
Contact contact = new Contact();
EntityKey contactKey =
new EntityKey("OrderDetails.Contact",
"contact_id", contact.Key.Id);
contact.EntityKey = contactKey;
contact.contact_id = contact.Key.Id;
order.Contact.Attach(contact); // throws an exception!
OrderDetails ordTable = new OrderDetails();
ordTable.AddToOrder(order);
int result = orgTable.SaveChanges();
When I go to attach, this exception is thrown:
"Attach is not a valid operation when the source object associated with this related end is in an added, deleted, or detached state. Objects loaded using the NoTracking merge option are always detached."
I know I'm probably missing a step or not fully understanding how the entity framework handles many-to-many relationships.
"Attach" is not allowed because you haven't saved the order yet. Calling "Add" tells Entity Framework that you want to insert a new contact. So you are left with only one option. You need to load the contact.
Here's the fastest way to do that:
OrderDetails context = new OrderDetails();
Contact contact = context.GetObjectByKey(new EntityKey("OrderDetails.Contact", "contact_id", existingContactId));
order.Contact.Add(contact);
If Order has a property Contact, then you can do:
order.Contact.Add(contact);
I would suggest making the property called Contacts rather than Contact, though.