I'm trying to build a Dynamics CRM 4 query so that I can get calendar events that are named either "Event A" or "Event B".
A QueryByAttribute doesn't seem to do the job as I cannot specify a condition where the field called "event_name" = "Event A" of "event_name" = "Event B".
When using the QueryExpression, I've found the FilterExpression applies to the Referencing Entity. I don't know if the FilterExpression can be used on the Referenced Entity at all. The example below is something like what I want to achieve, though this would return an empty result set as it will go looking in the entity called "my_event_response" for a "name" attribute. It's starting to look like I will need to run several queries to get this but this is less efficient than if I can submit it all at once.
ColumnSet columns = new ColumnSet();
columns.Attributes = new string[]{ "event_name", "eventid", "startdate", "city" };
ConditionExpression eventname1 = new ConditionExpression();
eventname1.AttributeName = "event_name";
eventname1.Operator = ConditionOperator.Equal;
eventname1.Values = new string[] { "Event A" };
ConditionExpression eventname2 = new ConditionExpression();
eventname2.AttributeName = "event_name";
eventname2.Operator = ConditionOperator.Equal;
eventname2.Values = new string[] { "Event B" };
FilterExpression filter = new FilterExpression();
filter.FilterOperator = LogicalOperator.Or;
filter.Conditions = new ConditionExpression[] { eventname1, eventname2 };
LinkEntity link = new LinkEntity();
link.LinkCriteria = filter;
link.LinkFromEntityName = "my_event";
link.LinkFromAttributeName = "eventid";
link.LinkToEntityName = "my_event_response";
link.LinkToAttributeName = "eventid";
QueryExpression query = new QueryExpression();
query.ColumnSet = columns;
query.EntityName = EntityName.mbs_event.ToString();
query.LinkEntities = new LinkEntity[] { link };
RetrieveMultipleRequest request = new RetrieveMultipleRequest();
request.Query = query;
return (RetrieveMultipleResponse)crmService.Execute(request);
I'd appreciate some advice on how to get the data I need.
The QueryExpression object has a Criteria property that you can set. If you're looking for "my_event" records that have name A or name B, just set it up like this:
ColumnSet columns = new ColumnSet();
columns.Attributes = new string[]{ "event_name", "eventid", "startdate", "city" };
ConditionExpression eventname1 = new ConditionExpression();
eventname1.AttributeName = "event_name";
eventname1.Operator = ConditionOperator.Equal;
eventname1.Values = new string[] { "Event A" };
ConditionExpression eventname2 = new ConditionExpression();
eventname2.AttributeName = "event_name";
eventname2.Operator = ConditionOperator.Equal;
eventname2.Values = new string[] { "Event B" };
FilterExpression filter = new FilterExpression();
filter.FilterOperator = LogicalOperator.Or;
filter.Conditions = new ConditionExpression[] { eventname1, eventname2 };
QueryExpression query = new QueryExpression();
query.ColumnSet = columns;
query.EntityName = EntityName.mbs_event.ToString();
query.Criteria = filter;
RetrieveMultipleRequest request = new RetrieveMultipleRequest();
request.Query = query;
return (RetrieveMultipleResponse)crmService.Execute(request);
If you're only looking for events that have responses, keep the LinkEntity part in, but move the FilterExpression over to the QueryExpression object like I have above.
Related
I need to update the list of users for a security role. How can I avoid re-associating an user that already has the role assigned?
I'm trying to build a query to get the role where user x is not in the role's list of users and then use it for the association if the user was not found. Here is what I have so far:
LinkEntity userRoles = new LinkEntity
{
LinkFromEntityName = "role",
LinkToEntityName = "systemuserroles",
LinkFromAttributeName = "roleid",
LinkToAttributeName = "roleid",
JoinOperator = JoinOperator.LeftOuter,
Columns = new ColumnSet(true),
EntityAlias = "userroles",
LinkCriteria =
{
Conditions =
{
new ConditionExpression{
//not sure how to build the "where user x does not exists"
}
}
}
};
QueryExpression roleQuery = new QueryExpression
{
EntityName = "role",
ColumnSet = new ColumnSet(true),
Criteria =
{
Conditions = {
new ConditionExpression {
AttributeName = "name",
Operator = ConditionOperator.Equal,
Values = { "RoleName"}
}
}
},
LinkEntities = { userRoles }
};
I need to build something like this query:
select * from role
where role.name = "RoleName"
and not exists
(select 1 from userRoles
where userRoles.roleid = role.roleid
and userRoles.user = "xyz")
Based on this post that explained it using Fetch XML, I was able to build this query that gets the role as long as the user I specify is not there:
LinkEntity userRoles = new LinkEntity
{
LinkFromEntityName = "role",
LinkToEntityName = "systemuserroles",
LinkFromAttributeName = "roleid",
LinkToAttributeName = "roleid",
JoinOperator = JoinOperator.LeftOuter,
Columns = new ColumnSet(true),
EntityAlias = "userroles",
LinkCriteria =
{
Conditions =
{
new ConditionExpression {
AttributeName = "systemuserid",
Operator = ConditionOperator.Equal,
Values = { "xyz" }
}
}
}
};
QueryExpression roleQuery = new QueryExpression
{
EntityName = "role",
ColumnSet = new ColumnSet(true),
Criteria =
{
Filters = {
new FilterExpression{
FilterOperator = LogicalOperator.And,
Conditions = {
new ConditionExpression{
EntityName = "systemuserroles",
AttributeName = "roleid",
Operator = ConditionOperator.Null
}
}
}
},
Conditions = {
new ConditionExpression {
AttributeName = "name",
Operator = ConditionOperator.Equal,
Values = { "RoleName"}
}
}
},
LinkEntities = { userRoles }
};
So far I can programmatically create a new Team and a new Area, but when I navigate to the TFS 2015 "Work" tab I see this error:
TF400509: No backlog iteration path was specified. You must select an iteration path.
So if I manually choose one iteration then I get:
TF400512: You have not selected any areas for your team. You must select at least one area before you can use features such as the product backlog, the task board or tiles.
Here's my code:
tpc.Authenticate();
// Create New Area
ICommonStructureService css = tpc.GetService<ICommonStructureService>();
string rootNodePath = string.Format("\\Onboarding\\Area");
var pathRoot = css.GetNodeFromPath(rootNodePath);
var newAreaPath = css.CreateNode("Area 51", pathRoot.Uri);
// Create new Team with Same Name
TfsTeamService tts = tpc.GetService<TfsTeamService>();
string newteamname = "Area 51";
string teamdescription = "Area 51 Team Description";
IDictionary<string, object> prop = new Dictionary<string, object>
{
{"Area", "Area 51"},
{"Iteration", "\\Onboarding\\Iteration\\Onboarding" }
};
tts.CreateTeam(onboardingProject.Uri.ToString(), newteamname, teamdescription, prop);
TfsTeamService teamService = tpc.GetService<TfsTeamService>();
ProjectInfo projectInfo = css.GetProjectFromName("Onboarding");
var allTeams = teamService.QueryTeams(projectInfo.Uri);
So the question again?
At what point can you set the Backlog Iteration for the new Area, and how/where do you select the new Area for the new Team?
You can add following codes to set the backlog iteration path:
TeamSettingsConfigurationService tscs = tpc.GetService<TeamSettingsConfigurationService>();
IEnumerable<TeamFoundationTeam> teams = tts.QueryTeams(projectInfo.Uri);
TeamFoundationTeam team = teams.Where(a => a.Name == "Area 51").FirstOrDefault();
var teamconfigs = tscs.GetTeamConfigurations(new[] { team.Identity.TeamFoundationId });
TeamConfiguration tconfig = teamconfigs.FirstOrDefault();
Console.WriteLine(tconfig.TeamName);
TeamSettings ts = tconfig.TeamSettings;
ts.IterationPaths = new string[] { string.Format("\\Onboarding\\Iteration 1") };
ts.BacklogIterationPath = string.Format("\\Onboarding\\Iteration 1");
TeamFieldValue tfv = new TeamFieldValue();
tfv.IncludeChildren = true;
tfv.Value = projectInfo.Name + "\\Area 51";
ts.TeamFieldValues = new TeamFieldValue[] { tfv};
tscs.SetTeamSettings(tconfig.TeamId,ts);
What you are looking for is TeamSettings Class, you can check case TFS 2012 API Set TeamSettings Programmatically of how to Set TeamSettings Programmatically:
// Set up default team sprint date and time
var teamConfig = _tfs.GetService<TeamSettingsConfigurationService>();
var css = _tfs.GetService<ICommonStructureService4>();
string rootNodePath = string.Format("\\{0}\\Iteration\\Release 1\\Sprint 1", _selectedTeamProject.Name);
var pathRoot = css.GetNodeFromPath(rootNodePath);
css.SetIterationDates(pathRoot.Uri, DateTime.Now.AddDays(-5), DateTime.Now.AddDays(7));
var configs = teamConfig.GetTeamConfigurationsForUser(new[] { _selectedTeamProject.Uri });
var team = configs.Where(c => c.TeamName == "Demo").FirstOrDefault();
var ts = team.TeamSettings;
ts.BacklogIterationPath = string.Format(#"{0}\Release 1", _selectedTeamProject.Name);
ts.IterationPaths = new string[] { string.Format(#"{0}\Release 1\Sprint 1", _selectedTeamProject.Name), string.Format(#"{0}\Release 1\Sprint 2", _selectedTeamProject.Name) };
var tfv = new TeamFieldValue();
tfv.IncludeChildren = true;
tfv.Value = _selectedTeamProject.Name;
ts.TeamFieldValues = new []{tfv};
teamConfig.SetTeamSettings(team.TeamId, ts);
Useful blog: http://blogs.microsoft.co.il/shair/2012/05/23/tfs-api-part-46-vs11-team-settings/
I have an object created by - new {name1 = "string1"}
I have to add additional members to it eg {name2 = "string2"} so that the final result is
{
name1 = "string1",
name2 = "string2"
}
You can either instantiate it all at once:
var someObj = new {name1 = "name 1", name2 = "name 2"};
Or you can do it in steps.
var someObj1 = new {name1 = "name 1"};
var someObj2 = new {name1 = someObj1.name1, name2 = "name 2"};
But no, you can't add properties/field to anonymous types at run-time or after it's been instantiated.
You have to create a new object, of a new anonymous type:
var obj1 = new {name1 = "string1"};
var obj2 = new {name1 = obj1.name1, name2 = "string2" };
I'm trying to use an email address to retrieve contact data. I'm already using this but i'm wondering how to extend it so that custom fields can also be returned:
public ContactInfo GetContactByEmail(string email, CrmService service)
{
QueryExpression query = new QueryExpression();
query.EntityName = "contact";
ColumnSet columns = new ColumnSet();
columns.Attributes.Add("contactid");
query.ColumnSet = columns;
query.Criteria = new FilterExpression();
query.Criteria.FilterOperator = LogicalOperator.And;
ConditionExpression condition = new ConditionExpression();
condition.AttributeName = "emailaddress1";
condition.Operator = ConditionOperator.Equal;
condition.Values = new object[] { email.Trim() };
query.Criteria.Conditions.Add(condition);
RetrieveMultipleRequest request = new RetrieveMultipleRequest();
request.Query = query;
ContactInfo contactInfo = new ContactInfo();
RetrieveMultipleResponse response = null;
response = (RetrieveMultipleResponse)service.Execute(request);
foreach (contact cont in response.BusinessEntityCollection.BusinessEntities)
{
contactInfo.contactid = cont.contactid.Value;
//Would also like to retrieve a custom attribute called ContactType (type int)
}
return contactInfo;
}
Any help or examples would be really appreciated. Thank you.
You just need to add additional values to the ColumnSet, e.g.
ColumnSet columns = new ColumnSet();
columns.Attributes.Add("new_contacttype");
Note: The name here should be the schema and not the display.
Examples:
Using Dynamic Entities.
Using the ColumnSet Class.
CrmService.RetrieveMultiple Method.
Currently I’m having some difficulties with using new Magento's soap v2 from c# interface.
With php i was able to do something like this:
$params["created_at"]["from"] = date("Y-m-d H:i:s",Functions::convert_time($dataDa));
$params["created_at"]["to"] = date("Y-m-d H:i:s",Functions::convert_time($dataA));
MageInterface::getSingleton()->shipmentList($params);
In this mode i was able to find list of orders which were created from $dataDa to $dataA without problems. With c# however it seems that only the last one of the selectors work.
My code:
var cpf = new complexFilter[2];
cpf[0] = new complexFilter
{
key = "created_at",
value = new associativeEntity
{
key = "to",
value = uxDataA.DateTime.ToString("yy-MM-dd HH:mm:ss")
}
});
cpf[1] = new complexFilter
{
key = "created_at",
value = new associativeEntity
{
key = "from",
value = uxDataDa.DateTime.ToString("yy-MM-dd HH:mm:ss")
}
});
var filters = new filters();
filters.complex_filter = cpf;
var risultato = mage.salesOrderList(sessionKey, filters);
In this mode only created_at->from criteria is taken in consideration (it's like second complex filter override previous one with the same key). Ideas?
Thanks in advance.
This works for me :
private filters addFilter(filters filtresIn, string key, string op, string value)
{
filters filtres = filtresIn;
if (filtres == null)
filtres = new filters();
complexFilter compfiltres = new complexFilter();
compfiltres.key = key;
associativeEntity ass = new associativeEntity();
ass.key = op;
ass.value = value;
compfiltres.value = ass;
List<complexFilter> tmpLst;
if (filtres.complex_filter!=null)
tmpLst = filtres.complex_filter.ToList();
else tmpLst = new List<complexFilter>();
tmpLst.Add(compfiltres);
filtres.complex_filter = tmpLst.ToArray();
return filtres;
}
and call
{
Mage_Api_Model_Server_V2_HandlerPortTypeClient clientSoap = new Mage_Api_Model_Server_V2_HandlerPortTypeClient();
string sessionId = clientSoap.login(LOG, PASS);
filters filtres = new filters();
filtres = addFilter(filtres, "status", "eq", "processing");
filtres = addFilter(filtres, "created_at", "from", "2014-09-07 08:00:00");
filtres = addFilter(filtres, "created_at", "to", "2014-09-07 00:00:00");
salesOrderEntity[] lst = clientSoap.salesOrderList(sessionId, filtres);
}
Solved, there was a bug (or the feature?) in mage\sales\order\api\v2.php
See more info in this thread: http://www.magentocommerce.com/boards/viewthread/70368/