I am very new to CRM development, i was trying to follow this article, i am a bit confused about below code, please check:
var xp = Xrm.Page;
function onLoad(context) {
var accountId = xp.data.entity.getId();
var mostRecentQuery = "/XRMServices/2011/organizationData.svc/ContactSet?
$select=FullName,JobTitle,EMailAddress1,Telephone1&$top=1&$orderby=CreatedOn
desc&$filter=ParentCustomerId/Id eq guid'" + accountId + "'";
getContact(mostRecentQuery, "MostRecent");
....
}
The above javascript function executes when AccountForm is opened. The first line gets the accountId. the next line is oData query.
Now check the ContactSet in this query, i am confused here, how we can retrieve the ContactEntity based on the GUID of AccountEntity?
I found the answer!
Actually there a Lookup 'Parent Customer' on ContactEntity, it represents the unique identifier of the account or contact associated with this contact, so we can select an Account/Contact as the Parent Customer of a contact.
So this given OData query actually retrieves the top 1 contact where this account is referenced.
I hope its clear.
Related
I perform the following query in Microsoft Graph:
var results = await SPLists["<my-list-name>"]
.Items
.Request()
.Expand("fields")
.GetAsync();
It gets the list items of a list I have in SharePoint. One of the columns in that list is of type "Person or Group". In the response from Microsoft Graph, it returns that column data like this (for example):
{
"LookupId": 335,
"LookupValue": "John Doe"
}
How do I take advantage of this data? How do I get the full profile of person with ID 355 using the Microsoft Graph? I need the email address of the person returned. How do I get that using the Microsoft Graph SDK?
The Look Id 335 is the Id in the SharePoint Hidden List named "User Information List", you can get the list guid using the request:
https://graph.microsoft.com/v1.0/sites/site-id/lists?$filter=DisplayName eq 'User Information List'
Then use the list guid in the endpoint below to get the detail email address:
https://graph.microsoft.com/v1.0/sites/site-id/lists/UserInformationListId/items/335
Here is a similiar thread for your reference:
How to get user from User field LookupId
I need to make a generic exporter/importer from a Microsoft CRM 2011 system and I cant find out if a LookupAttribute is a one-to-one- or one-to-many-relation.
E.x.
I have an Entity called an "E-mail".
And e-mail can have one "From" (which is a lookup attribute that does its lookup into multiple other Entity-lists)
It can then have multiple "To" (also referencing out into multiple entity-lists as a lookup attribute).
The conclusions I just made are stuff that i figured out by using the web portal for MS CRM. I just cant find any way to see in the metadata of these Entities or Attributes if its a one-to-one- or a on-to-many-relation.
https://msdn.microsoft.com/en-us/library/gg509035.aspx#BKMK_CreateLookupAttribute
I've looked at this example on how to create these kinds of relations, but it hasnt gotten me any futher.
Does anyone have any experience with generic export/import with MS CRM 2011 that can help me?
CRM has a two types of relationships:
One to many: a lookup on one entity, a grid on the other.
Many to many: a grid on both entities.
There is no such thing as a one to one relationship. You are looking at a lookup. 90% of the lookups you see are simple, you can select one record of one entity type.
However, there are special system field lookups, named activity party. These muddy the waters a little. Some activity party lookups allow multiple record selections, some link to entities of multiple types. Which means you can have an activity party lookup with multiple records of multiple entity types. I suppose you could call this a "one to many (records) of many (entities)".
For example on an email; the To field can be populated with multiple account and contact records. Whilst the From field can only have one record, but that can be a system user or queue. The To and From are both examples of activity party lookups.
So in terms of what you are trying to do, you need to examine:
AttributeMetadata.AttributeType to see if its a party list.
LookupAttributeMetadata.Targets to see what record types are allowed in the lookup.
The following code shows how to do this for a couple of different fields.
RetrieveAttributeRequest attributeRequest = new RetrieveAttributeRequest
{
EntityLogicalName = "email",
LogicalName = "to",
RetrieveAsIfPublished = true
};
RetrieveAttributeResponse result = Service.Execute(attributeRequest) as RetrieveAttributeResponse;
Trace.WriteLine("Email - To");
Trace.WriteLine("AttributeMetadata.AttributeType: " + result.AttributeMetadata.AttributeType);
Trace.WriteLine("LookupAttributeMetadata.Targets: " + ((LookupAttributeMetadata)result.AttributeMetadata).Targets.CollectionToString(", "));
attributeRequest = new RetrieveAttributeRequest
{
EntityLogicalName = "email",
LogicalName = "from",
RetrieveAsIfPublished = true
};
result = Service.Execute(attributeRequest) as RetrieveAttributeResponse;
Trace.WriteLine("Email - From");
Trace.WriteLine("AttributeMetadata.AttributeType: " + result.AttributeMetadata.AttributeType);
Trace.WriteLine("LookupAttributeMetadata.Targets: " + ((LookupAttributeMetadata)result.AttributeMetadata).Targets.CollectionToString(", "));
attributeRequest = new RetrieveAttributeRequest
{
EntityLogicalName = "account",
LogicalName = "parentaccountid",
RetrieveAsIfPublished = true
};
result = Service.Execute(attributeRequest) as RetrieveAttributeResponse;
Trace.WriteLine("Account - Parent Account Id");
Trace.WriteLine("AttributeMetadata.AttributeType: " + result.AttributeMetadata.AttributeType);
Trace.WriteLine("LookupAttributeMetadata.Targets: " + ((LookupAttributeMetadata)result.AttributeMetadata).Targets.CollectionToString(", "));
And the output:
Email - To
AttributeMetadata.AttributeType: PartyList
LookupAttributeMetadata.Targets: account, contact, lead, queue, systemuser
Email - From
AttributeMetadata.AttributeType: PartyList
LookupAttributeMetadata.Targets: queue, systemuser
Account - Parent Account Id
AttributeMetadata.AttributeType: Lookup
LookupAttributeMetadata.Targets: account
Do you know is there any like a global reference book of MS CRM entities in the system?
I need to resolve entity id to the entity type without checking every single entity for presence of given GUID.
Is it possible?
I don't know of any supported way, but I believe you could to a SQL query on the PrincipalObjectAccess table in the database and retrieve the value of ObjectTypeCode where ObjectId is the GUID.
For annotation you need to look at the field objecttypecode to determine the entity type of objectid.
You can either generate a list of entity logical names and object type codes in your code as a Dictionary object (this will give you the fastest performance but requires you know all the entity types that will be in the system at the time you compile) or (if you are on CRM 2011 UR12+ or CRM 2013) you can do a MetadataQuery.
You can read more about doing a metadata query here: http://bingsoft.wordpress.com/2013/01/11/crm-2011-metadata-query-enhancements/
Sample code for your requirement:
var objTypeCode = [INTEGER] //Make this this the annotation.objecttypecode
MetadataFilterExpression entityFilter = new MetadataFilterExpression(LogicalOperator.And);
EntityFilter.Conditions.Add(new MetadataConditionExpression("ObjectTypeCode", MetadataConditionOperator.Equals, objTypeCode);
EntityQueryExpression entityQueryExpression = new EntityQueryExpression()
{
Criteria = entityFilter
};
RetrieveMetadataChangesRequest retrieveMetadataChangesRequest = new RetrieveMetadataChangesRequest()
{
Query = entityQueryExpression,
ClientVersionStamp = null
};
RetrieveMetadataChangesResponse response = (RetrieveMetadataChangesResponse)orgService.Execute(retrieveMetadataChangesRequest);
You can reduce the metadata retrieved, for better performance, as shown here: How to get the CRM Entity Name from the Object Type Code of a RegardingID?
I have a requirement to sync some entities (account, lead, contact etc) to a database table outside of the crm database but on the same server. I am looking for a supported way for doing this. Here's what I have tried, that don't work:
I first created table in the outside database that matches the schema from dbo.account (view). Then I wrote post create, post update, post assign and post delete plugins to create, update or delete the record in the outside table (using ADO.Net). I have written the plugin in the most generic way so that it can be registered for any entity with minimum changes to the plugin (by not hardcoding the field names). Doing it this way, the problem I am running into is with the fields that are foreign key to other tables. Eg. in dbo.account, there are fields like PrimaryContactId and PrimaryContactIdName, PreferredSystemUserId and PreferredSystemUserIdName, ParentAccountId and ParentAccountIdName etc. In the input parameters for the plugin, the xxxxId fields are available when they are updated, but not the 'xxxxIdName' fields. Because of which I am not able to 'sync' the table as is.
Is there a solution to make my plugin solution work?
Is there a better supported way for having a sync table?
Thanks in advance,
PS: 1. The data sync has to be in real time
PS: 2. Here is my function to get the query that does the update
private static string PrepareUpdateQuery(ITracingService tracingService, IEnumerable<KeyValuePair<string, object>> attributeCollection, string entityName, string entityIdName)
{
var query = "Update MainDb.MSCRM." + entityName + " set ";
foreach (KeyValuePair<string, object> keyValuePair in attributeCollection)
{
tracingService.Trace("Key: {0}", keyValuePair.Key);
if (keyValuePair.Key != entityIdName && keyValuePair.Key != "modifiedonbehalfby")
{
query = query + keyValuePair.Key + " = ";
if (keyValuePair.Value == null)
query = query + "null, ";
else
{
var typeOfValue = keyValuePair.Value.GetType().Name;
tracingService.Trace("typeOfValue: {0}", typeOfValue);
switch (typeOfValue)
{
case "EntityReference":
query = query + "'" + ((EntityReference)keyValuePair.Value).Id + "', ";
break;
case "OptionSetValue":
query = query + ((OptionSetValue)keyValuePair.Value).Value + ", ";
break;
case "BooleanManagedProperty":
query = query + (((BooleanManagedProperty)keyValuePair.Value).Value ? "1" : "0") + ", ";
break;
default:
query = query + "'" + keyValuePair.Value + "', ";
break;
}
}
}
}
return query;
}
If all you're after is the name of the entity that is an attribute on your currently executing plugin, the EntityReference object has a Name property that should contain that name. If it doesn't you you can query CRM with the id and logical name to get any value that you're looking for on the referenced entity.
Edit 1
If you're just moving the data, why even bother setting the referenced name? I'd removed those names from your database table, and just create a view that looks up the corresponding entity's name. It's what CRM is doing. It also makes your other database more normalized. IE. If you update the name of an entity that is referenced by another entity, you will have to search for and update all of those names...
the xxxIdName fields are just a helper for the views really, you can easily figure out what they
should contain.
For example, say you have an account 'some company' with a primary contact called 'bob bobson'.
when processing the account entity the primarycontactId will be a guid and the primarycontactIdName will be 'bob bobson', the accountIdName will be 'some company'.
easiest way to do this in your plugin is to look up the related entity and get the value from there - 90% of the time it's just the name field.
you also need to consider however if you are doing the right thing in using the CRM schema, perhaps it would be better to copy only the fields you need and use your own schema for the sync table.
UPDATE: just saw your code, you are overwritting the value contained in query and not setting it back to the base query, so you will get odd results/errors on the second pass through the foreach
If you're dead set on putting the related entity name in the primary entity table you can always grab it like this:
var entityEntityRef = (EntityReference)keyValuePair.Value;
var relatedEntity = service.Retrieve(entityRef.LogicalName, entityRef.Id, new ColumnSet(true));
Now relatedEntity as all the attributes available. You'll mostly be looking for the Name field, but some entities are different, like contact which uses the full name field I believe.
You can, in fact, register a single plugin for all entities (checking, of course, that the one that's firing the message is in the list of treated ones).
IEnumerable<String> supportees = new String[]{ "account", "contact" };
if(!supportees.Any(element
=> element == targetLogicalName))
return;
As for the linked entities, you have three choices.
Just skip them. Not full data sync but easies to implement.
Store the guids only. Data sync is instance-wide - limited but moderately easy.
Get all the linked data. Full information but a recursive PIA to develop.
How do I query for all trac tickets related to a user. i.e. all tickets for which the tickets were once assigned, assigned now, created , etc etc
Create custom queries to the ticket_change table. Some SQL required. For assigned once/now, look for rows where field='owner', newvalue column contains the user name the ticket was assigned to. For created tickets, just query by reporter in the ticket table.
Example:
SELECT p.value AS __color__,
id AS ticket, summary, component, version, milestone,
t.type AS type, priority, t.time AS created,
changetime AS _changetime, description AS _description,
reporter AS _reporter
FROM ticket t, enum p, ticket_change c
WHERE p.name = t.priority AND p.type = 'priority'
AND c.field = 'owner'
AND c.newvalue = '$USER'
AND c.ticket = t.id
ORDER BY p.value, milestone, t.type, t.time
You can express this with a TraqQuery expression. E.g. if you want the columns id, summary and status to show up and query all the tickets for the currently logged in user ($USER) then use the following query.
query:?col=id
&
col=summary
&
col=status
&
owner=$USER
However this query assumes that the owner hasn't been the same during the lifetime of a ticket (since ownership can be changed).
If you want a specific user then replace $USER with the actual username. Also if you're using the Agilo plugin you can easily create new queries on the fly via the web-UI. This is done by looking at a report and adding filters to the report.