Retrieve all child/descendant/related entities programmatically - c#

How do I retrieve all of the related entities of a source entity in CRM Dynamics 2011, in C#?
thanks

FetchXml is overkill for this requirement, but obviously if you want to construct the FetchXml and use it for your QueryBase in place of the QueryExpression I'm showing you are free to do that. The logic remains the same.
//Assumes you have a Entity() object of the parent entity
//somehow you have to know the parent entity record's Id
Guid parentId = parentEntity.Id;
var query = new QueryExpression("new_childentity");
query.Criteria.AddCondition(new ConditionExpression("new_lookupfield", ConditionOperator.Equal, parentId));
query.ColumnSet = new ColumnSet(true);
var results = service.RetrieveMultiple(query);
if (results.Entities.Any())
{
//Do your processing here
}
else
{
//Do whatever when there are no child entities
}

Related

Querying product/pricing information against Dynamics 365 tenant using the C# SDK

I am trying to query product related information in a Dynamics 365 tenant (Version 9.2.22101.170) and with Version 9.0.2.46 of the Microsoft.CrmSdk. Mostly I am interested in querying products by the product number to retrieve price information, but later on, I would introduce more parameters. The below is one of the many methods I've tried (I am aware I am projecting only the name for the time being, eventually I would require price information etc):
var cols = new ColumnSet(new String[] { "name" });
QueryByAttribute query = new QueryByAttribute("product");
query.ColumnSet = cols;
query.Attributes.AddRange("productnumber");
query.Values.AddRange("100002");
var results = service.RetrieveMultiple(query);
if (results != null)
{
var entities = results.Entities.ToList();
if (entities != null)
{
var productEnt = (Product)entities.FirstOrDefault();
Console.WriteLine(productEnt.Name);
}
}
This is the error message returned, on the RetrieveMultiple call:
The entity with a name = 'product' with namemapping = 'Logical' was not found in the MetadataCache. MetadataCacheDetails: ProviderType=Dynamic, StandardCache=True, IsLoadedInStagedContext = False, Timestamp=8343791, MinActiveRowVersion=8343791
The same message is returned when calling any other method. It's clear that the issue is not the query, or the columns being returned but the "product".
Sure enough, I am using the below method to get the list of entity names, and the word "Product" does not show up. I think this explains the error message.
public static EntityMetadata[] GetEntities(IOrganizationService organizationService)
{
Dictionary<string, string> attributesData = new Dictionary<string, string>();
RetrieveAllEntitiesRequest metaDataRequest = new RetrieveAllEntitiesRequest();
RetrieveAllEntitiesResponse metaDataResponse = new RetrieveAllEntitiesResponse();
metaDataRequest.EntityFilters = EntityFilters.Entity;
// Execute the request.
metaDataResponse = (RetrieveAllEntitiesResponse)organizationService.Execute(metaDataRequest);
var entities = metaDataResponse.EntityMetadata;
return entities;
}
Is this a permission issue? Do I need to do some extra loading prior to the query? How do you query product/pricing related information in a Dynamics 365 tenant?
I tried searching for related information online, but I was surprised to practically find almost nothing related to Products.
you are using QueryByAttribute rather you should be using QueryExpression
Try below query and it should help.
// Define Condition Values
var query_productnumber = "100002";
// Instantiate QueryExpression query
var query = new QueryExpression("product");
query.Distinct = true;
// Add columns to query.ColumnSet
query.ColumnSet.AddColumns("productid", "name");
// Define filter query.Criteria
query.Criteria.AddCondition("productnumber", ConditionOperator.Equal, query_productnumber);
var results = service.RetrieveMultiple(query);
if (results != null)
{
var entities = results.Entities.ToList();
if (entities != null)
{
var productEnt = (Product)entities.FirstOrDefault();
Console.WriteLine(productEnt.Name);
}
}

C# crm linQ LinkEntities

I need to query from a CRM entity some values where a linked entity contains a string inside its name.
I try to explain:
I have new_supplycontract table.
This table, has an EntityReference named new_pod
The new_pod entity, has two fields: new_citypod and new_street
new_citypod points to another entity named new_city
new_street points to another entity named new_street
I need to query the new_supplycontract table to retrieve only the records whose new_pod contains a street which name contains a string I pass and a city which name contains another string i pass.
I know this code works for retrieving all new_supplycontract entities whose two text fields "new_city" and "new_address" are like to two strings passed.
QueryExpression query = new QueryExpression(new_supplycontract.EntityLogicalName);
query.ColumnSet = new ColumnSet(true);
query.Criteria.AddCondition("new_city", ConditionOperator.NotNull);
query.Criteria.AddCondition("new_address", ConditionOperator.NotNull);
query.LinkEntities.Add(new LinkEntity(new_supplycontract.EntityLogicalName, "new_comune", "new_city", "new_comuneid", JoinOperator.Inner));
query.LinkEntities[0].Columns.AddColumns("new_name");
query.LinkEntities[0].EntityAlias = "comuneTemp";
query.LinkEntities[0].LinkCriteria.AddCondition("new_name", ConditionOperator.Like, "%" + comune + "%");
query.LinkEntities.Add(new LinkEntity(new_supplycontract.EntityLogicalName, new_via.EntityLogicalName, "new_address", "new_viaid", JoinOperator.Inner));
query.LinkEntities[1].Columns.AddColumns("new_name");
query.LinkEntities[1].EntityAlias = "viaTemp";
query.LinkEntities[1].LinkCriteria.AddCondition("new_name", ConditionOperator.Like, "%" + via + "%");
DataCollection<Entity> entities = service.RetrieveMultiple(query).Entities;
But I don't really know how to use this code for my goal. I don't know how to filter an entityreference's entityreference.
Any help will be appreciated
LinkedEntities can have nested LinkedEntities in CRM 2011. This was changed since 2013 where an EntityName attribute was introduced and there wasn't a need for having nested entities.
But basically, you could start from the supplycontract entity, then add a linked entity against your new_pod entity. From that Linked Entity, you'll need to add 2 linked entities, one to the new_city entity and another one to the new_street entity. Each of these 2 linked entities will need a contains condition expression where you pass the 2 strings you want to use for filtering.
Ex:
QueryExpression query = new QueryExpression(new_supplycontract.EntityLogicalName);
query.ColumnSet = new ColumnSet(true);
var le = query.LinkEntities.Add(new LinkEntity(new_pod.EntityLogicalName, "new_pod", "new_pod", "new_podid", JoinOperator.Inner));
var lePod = le.LinkEntities.Add(new LinkEntity(new_pod.EntityLogicalName, "new_city", "new_citypod", "new_cityid", JoinOperator.Inner));
var leCity = le.LinkEntities.Add(new LinkEntity(new_pod.EntityLogicalName, "new_street", "new_street", "new_streetid", JoinOperator.Inner));
//Add conditions to each nested linked entity now as above.
Now, I personally prefer LINQ cause the query is much more easier to read than using LinkedEntities.
Hope this helps.
I've ran into countless issues with LINQ to CRM, mostly due to my misunderstanding of how it works. Unfortunately, Query Expressions are extremely verbose and hard to read. I created and use the DLaB.Xrm library to make my life simpler (and more typed, I love me some EarlyBound Dev)
Here is your query using DLaB.Xrm:
var qe = QueryExpressionFactory.Create<new_supplycontract>();
var podLink = qe.AddLink<new_pod>(new_supplycontract.Fields.new_Pod, new_pod.Fields.Id);
podLink.AddLink<new_city>(new_pod.Fields.new_citypod, // This is the attribute of the "from" entity to join on
new_city.Fields.Id, // This is the attribute of the "to" entity to join on. If name is identical, this parameter can be removed
new ColumnSet(new_city.Fields.new_name)) // AliasedValue to add to the result
.LinkCriteria.AddCondition("new_name", ConditionOperator.Like, "%" + comune + "%");
podLink.AddLink<new_street>(new_pod.Fields.new_street,
new_street.Fields.Id,
ColumnSet(new_street.Fields.new_name))
.LinkCriteria.AddCondition("new_name", ConditionOperator.Like, "%" + via + "%");
var leads = service.GetEntities(qe);
You need to chain the link entities. Here's an example:
ConditionExpression condition3 = new ConditionExpression();
...
LinkEntity link3 = new LinkEntity();
...
link3.LinkCriteria.Conditions.Add(condition3);
ConditionExpression condition2 = new ConditionExpression();
...
LinkEntity link2 = new LinkEntity();
...
link2.LinkCriteria.Conditions.Add(condition2);
LinkEntity link1 = new LinkEntity();
...
link1.LinkEntities.Add(link2);
link1.LinkEntities.Add(link3);
QueryExpression query = new QueryExpression("");
...
query.LinkEntities.Add(link1);
DataCollection<Entity> entities = service.RetrieveMultiple(query).Entities;
It helps to write them separately and use .Criteria.Conditions.Add() instead of .Criteria.AddCondition()

How can I get all the activities for an account?

I have a program that I have written that gets the data from Dynamics CRM 2013 online. But I am running into one issue where a query to get the activities for an account only returns a subset instead of all the activities. The query expression is this
private QueryExpression CreateActivityQuery(Guid id)
{
QueryExpression query = new QueryExpression()
{
Distinct = true,
EntityName = Cd2Sf.ActivityPointer.EntityLogicalName,
ColumnSet = new ColumnSet(true)
};
query.Criteria = new FilterExpression();
query.Criteria.AddCondition("regardingobjectid", ConditionOperator.Equal, id);
return query;
}
Where the id is the account id. I had first tried using the activityparty where the party id was equal to the account id and then I tried using the regardingobjectid and lastly then tried the Rollup method with the extended related entities but all produce the same result.
#region Create RollupRequest
// Create RollupRequest
RollupRequest rollupRequest = new RollupRequest();
rollupRequest.Query = qexp;
rollupRequest.Target = new EntityReference("account", acct.Id);
rollupRequest.RollupType = RollupType.Extended;
#endregion Create RollupRequest
#region Execute RollupRequest
// Execute RollupRequest
RollupResponse rollupResponse = (RollupResponse)service.Execute(rollupRequest);
#endregion Execute RollupRequest
#region Show RollupResponse results
ShowActivities(rollupResponse.EntityCollection, percent);
#endregion Show RollupResponse results
Do I need to use contacts as well to get all the activities that are associated to the account, i.e. use the activityparty and match the to/from/sender/cc/bcc/etc with contacts for an account? I had tried to use the contact id as the regardingobjectid but that still does not account for all of the activities.
It appears that the web page for dynamics crm online when viewing the account and the activities that are on that page are more than what the above query gets alone.
How do I get the other activities, the ones that seem to be not directly related to the account?
My original answer doesn't answer the question - I've abbreviated it here.
Sarah Champ's post on using outer joins in your fetchxml is really good:
http://blogs.msdn.com/b/crminthefield/archive/2013/07/01/dynamic-activity-reporting-using-fetchxml.aspx
You have to use a FetchExpression rather than a QueryExpression, but you can use it the same way with a RetrieveMultipleRequest now.
FetchExpression example:
string fetch = "<fetch xml string>"
var query = new FetchExpression(fetch);
var request = new RetrieveMultipleRequest();
request.Query = query;
var entities = ((RetrieveMultipleResponse)service.Execute(request)).EntityCollection.Entities;
foreach (var entity in entities)
{
Console.WriteLine(entity.GetAttributeValue<string>("subject"));
}

Retrieve Filter Conditions in Views in CRM 2011 using query expression (C#)

Am developing a windows form which resembles the look up view on CRM 2011.
For this I do the following
1) Show the relevant records (of opportunity entity) in a datagirdview
2) Also have a dropdownlist that binds to the views (View.Name) to allow the user to choose the view according to which i intend to change the filter on my datagrid view.
Am stuck with the following.Am able to retrieve the views on the "Opporutunity" entity using the following code
ConditionExpression condition1 = new ConditionExpression()
{
AttributeName = "querytype",
Operator = ConditionOperator.Equal,
Values = { 0 }
};
ConditionExpression condition2 = new ConditionExpression()
{
AttributeName = "returnedtypecode",
Operator = ConditionOperator.Equal,
Values = { Opportunity.EntityTypeCode }
};
FilterExpression filter = new FilterExpression();
filter.Conditions.Add(condition1);
filter.Conditions.Add(condition2);
QueryExpression queryToRetrieveViews = new QueryExpression
{
ColumnSet = new ColumnSet("savedqueryid", "name", "querytype", "isdefault", "returnedtypecode", "isquickfindquery"),
EntityName = SavedQuery.EntityLogicalName,
Criteria = filter
};
RetrieveMultipleRequest retrieveSavedViewsRequest = new RetrieveMultipleRequest { Query = queryToRetrieveViews };
RetrieveMultipleResponse retrieveSavedViewsResponse = (RetrieveMultipleResponse)crm.Execute(retrieveSavedViewsRequest);
DataCollection<Entity> savedViews = retrieveSavedViewsResponse.EntityCollection.Entities;
foreach (Entity ent in savedViews){...}
I did a quick watch but am unable to find the attribute that has the filter conditions as present in CRM. I mean what i intend to look at is something like this sayfor e.g. open opportunities the filter would be "statecode=0".
Is it possible to fetch the associated filters? -sorry by Associated filters i mean filters of the view
You can filter by whatever attribute you'd like so I'm not sure what you mean by the associated filters. If you mean the filter of the actual view you won't find it. Views are stored in XML, so you'll have to retrieve the the FetchXML for the saved view and parse the XML to see it's filter.

How to query multiple entities with a single QueryExpression

I am trying to run a microsoft dynamics crm 4.0 query. This works as expected when I generate a QueryExpression for "ONE" specific entity as I had done before. The issue however is how do i define more than one entity so i can apply logic that i have in another method? An example or illistration would be helpful.
so what i have is in this format:
static BusinessEntityCollection GetData(CrmService service)
{
cols = new ColumnSet();
cols.Attributes = new string[] { "x", "y", "z"};
FilterExpression filter = new FilterExpression();
filter.FilterOperator = LogicalOperator.And;
QueryExpression query = new QueryExpression();
query.EntityName = EntityName.incident.ToString();
// i am trying to add something like the below
query.EntityName = EntityName.account.toString();
query.ColumnSet = cols;
query.Criteria = filter;
return service.RetrieveMultiple(query);
}
The restriction I am facing is I can only query one entity and I need a solution or workaround to access and query multiple entities. Your help is much appreciated.
Simple answer: you can't. You could only query one entity at one time.
A query expression is used for single-object searches, for example, to search for all accounts that match certain search criteria.
See how to build queries.
You have to combine multiple requests for the entities you would like to get.
The same restriction exists for FetchXML. It is basically the serialized form of a QueryExpression. See how to use FetchXML

Categories