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()
Related
I have a number of spatial entities in a table, with a geometry field called Boundaries. I want to produce a GeoJson file with the simplified shapes/geometries.
This is my first attempt:
var entities = await db.Entities.ToListAsync();
dynamic geoJson = new ExpandoObject();
geoJson.type = "FeatureCollection";
var features = new List<dynamic>();
foreach (var entity in entities)
{
// simplify (uses SqlGeometry.Reduce)
var simplified = Utilities.Geo.Simplify(entity.Boundaries, tolerance);
// convert to GeoJSON4EntityFramework.Feature with the appropriate Id
var feature = Utilities.Geo.GetFeature(simplified, entity.Id);
features.Add(feature);
}
geoJson.features = features;
return geoJson;
The problem with the result is that, because the geometries are simplified individually, the boundaries aren't common, as shown below:
A second attempt is to combine the entities first, then simplify, then output as GeoJson:
var entities = await db.Entities.ToListAsync();
// bit of a hack to union all the boundaries
DbGeometry allBoundaries = null;
for (var i = 0; i < entities.Count; i++)
{
if (i == 0) allBoundaries = entities[i].Boundaries;
else allBoundaries = allBoundaries.Union(entities[i].Boundaries);
}
// simplify (uses SqlGeometry.Reduce)
var simplified = Utilities.Geo.Simplify(allBoundaries, tolerance);
dynamic geoJson = new ExpandoObject();
geoJson.type = "FeatureCollection";
var features = new List<dynamic>();
// convert to GeoJSON4EntityFramework.Feature with the (in)appropriate Id
var feature = Utilities.Geo.GetFeature(simplified, "ALL");
features.Add(feature);
geoJson.features = features;
return geoJson;
However, the .Union is combining the entities into a single entity, despite what is said here that this doesn't happen. (I also then don't have the opportunity to put an Id on each feature, so just used 'ALL' for now). The result is the completely merged shape:
So the question is: how do I combine the boundaries across rows, then simplify, then produce as a feature collection, with each feature having the
correct Id, as can be done in MapShaper (shown below)?
Looks like this is not possible in SQL Server.
You need to convert the geometries to topologies, then simplify, then match back to the original geometries to preserve the properties/attributes/id/etc.
See: https://trac.osgeo.org/postgis/wiki/UsersWikiSimplifyWithTopologyExt
SQL Server doesn't have support for Topologies.
EDIT
I'm working on the code below, which converts polygons (not multipolygons) to linestrings, unions the linestrings to effectively get a topology layer, then simplifies that. It works really well, but the difficulty is not in converting the multilinestrings to multipolygons, which might need a tool like this.
select
geometry::STGeomFromText(replace(replace(e1.boundaries.STAsText(), 'POLYGON (', 'LINESTRING '), '))', ')'), 4326)
.STUnion(geometry::STGeomFromText(replace(replace(e2.boundaries.STAsText(), 'POLYGON (', 'LINESTRING '), '))', ')'), 4326))
.STUnion(geometry::STGeomFromText(replace(replace(e3.boundaries.STAsText(), 'POLYGON (', 'LINESTRING '), '))', ')'), 4326))
.Reduce(0.1)
from entities e1
cross join entities e2
cross join entities e3
where e1.code = 'dc7'
and e2.code = 'dc6'
and e3.code = 'dc8'
EDIT
Using NetTopologySuite, it can be done. I've written it up here. Using the Polygonizer, you can convert the linestrings back to polygons. Then you have to match the polygons back to the originals by using a ratio of area intersection, and then (if matched) you can re-associate the properties.
I am trying to get the id of a marketing list created in Microsoft Dynamics based on the list's name. I will then use the id to add crm contacts to the list (this I can do fine using the id of the list)
I can't find any instructions in the documentation that explains how to do this. I have tried the following code but i get the error that no entity by that name exists:
var request = new RetrieveRequest();
request.Target = new EntityReference("new list 1", listId);
RetrieveResponse response = _organizationService.Execute(request) as RetrieveResponse;
What I am ultimately trying to do is make it possible for an administrator of the crm to identify the marketing list that a user should be added to when they fill in a newsletter form on our website. I think it will be too much to ask them to find the guid of the marketing list (it took me a bit of work to find it myself)
can anyone share some code to either get the id of a list using the list name as the identifier or let me know if its possible to add a contact to a list using the list name instead of the id?
The following code gets all lists in Dynamics with a name of "new list 1". It then stores the Id of the first list returned if one or more matches were found, or Guid.Empty if no matches were found. In your scenario there should be always be one and only one match.
var query = new QueryExpression
{
EntityName = "list",
ColumnSet = new ColumnSet(false)
};
query.Criteria.AddCondition("name", ConditionOperator.Equal, "new list 1";
var matchingLists = _organizationService.RetrieveMultiple(query);
var defaultListId = matchingLists?.Entities.FirstOrDefault()?.Id ?? Guid.Empty;
To retrieve the entity record using RetrieveRequest, schema name of that entity (DB table) should be passed as first parameter and primary key (GUID) as second. For Marketing list it is list & listid. You should also mention ColumnSet.
request.Target = new EntityReference("list", listId);
But to achieve what you want, you have to use either querybyattribute or queryexpression, then RetrieveMultiple will help you to get the Id from name of list.
FilterExpression filter = new FilterExpression();
filter.FilterOperator = LogicalOperator.And;
filter.AddCondition(new ConditionExpression("name", ConditionOperator.Equal, "new list 1"));
QueryExpression query = new QueryExpression("list");
query.Criteria.AddFilter(filter);
var result = Context.SystemService.RetrieveMultiple(query);
After that use AddListMembersListRequest or AddMemberListRequest to add members to that list.
// Add a list of contacts to the marketing list.
var addMemberListReq = new AddListMembersListRequest
{
MemberIds = new[] { _contactIdList[0], _contactIdList[2] },
ListId = listId
};
_serviceProxy.Execute(addMemberListReq);
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
}
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.
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