Dynamics 365 API link between ActivityPointer and activitytypecode global option set - dynamics-crm

I am reading data from the ActivityPointer entity in Dynamics 365 via the API and I want to link the activitytypecode field value to the activitypointer_activitytypecode global option set, which I believe is the correct one. However the values don't seem to match. In the ActivityPointer.activitytypecode field I have values such as:
phonecall
bulkoperation
email
appointment
task
But those values don't appear in the option set definition, using this query: GlobalOptionSetDefinitions(Name='activitypointer_activitytypecode')
The option set has the code values (e.g. 4202 for Email) and the different descriptions in all languages, but nothing matches back to the values on ActivityPointer

Optionset is just key value pairs (4202: Email and so on), If you want to get the formatted text value of optionset (Email, Fax, etc) from your web api query results - then you have to use activitytypecode#OData.Community.Display.V1.FormattedValue to get it. Read more
I recommend this article for complete understanding of CRM activities.
If you are looking for the code integer value in your resultset, that seems to be an issue and the result is not the expected one - old SO thread

The problem is that if you are reading activitytypecode in code, then you will know that you get a string value. This is the logical name of the activity entity, e.g. "email", "phonecall" etc.
If you look at the definition of activitytypecode in Power Apps then it shows it as "Entity name" (i.e. text) but using the classic solution editor it shows as the global activitypointer_activitytypecode option set, which contains values for "Email", "Phone Call" etc.
I am sure that there should be a simple way of converting from activitytypecode (i.e. entity name) to activitypointer_activitytypecode (i.e. option set), but I've yet to find it.
What I am doing is retrieving the global activitypointer_activitytypecode option set, so I have access to all of the text values. Then retrieve details about the entity indicated by activitytypecode, specifically what is of interesting is the display name. Then loop through the option set looking for a case-insensitive match on display name.
This is my C# code:
public int? GetActivityType(IOrganizationService service, string activityTypeCode)
{
// Get all activity types.
var optionSetRequest = new RetrieveOptionSetRequest()
{
Name = "activitypointer_activitytypecode"
};
var optionSetResponse = (RetrieveOptionSetResponse)service.Execute(optionSetRequest);
var optionSetMetadata = (OptionSetMetadata)optionSetResponse.OptionSetMetadata;
var optionValues = new Dictionary<string, int?>(StringComparer.OrdinalIgnoreCase);
foreach (var option in optionSetMetadata.Options)
{
foreach (var optionLabel in option.Label.LocalizedLabels)
{
optionValues[optionLabel.Label] = option.Value;
}
}
// Get the display name for the activity.
var retrieveEntityRequest = new RetrieveEntityRequest
{
EntityFilters = EntityFilters.Entity,
LogicalName = activityTypeCode
};
var retrieveEntityResponse = (RetrieveEntityResponse)service.Execute(retrieveEntityRequest);
LocalizedLabelCollection entityLabels = retrieveEntityResponse.EntityMetadata.DisplayName.LocalizedLabels;
// Look up the display name in the option set values.
foreach (var entityLabel in entityLabels)
{
if (optionValues.TryGetValue(entityLabel.Label, out int? value))
{
return (Schema.GlobalOptionSet.ActivityType?)value;
}
}
// If we get here then we've failed.
return null;
}
That is making two API calls, so best avoided in any situations where performance might be an issue. I'm not saying the code is perfect, but it hasn't let me down yet. Even so, I would recommend making do with the logical names provided by activitytypecode if you can.

Related

Is Dynamic LINQ still in use and suitable for narrowing-down search results?

I am developing an ASP.NET MVC3 application in C#.
I am trying to implement in my application a "narrow-down" functionality applied the result-set obtained from a search.
In short, after I perform a search and the results displayed in the center of the page, I would like to have on the left/right side of the page a CheckBoxList helper for each property of the search result. The CheckBox of each CheckBoxList represent the distinct values of the property.
For instance if I search Product and it has a Color property with values blue, red and yellow, I create a CheckBoxList with text Color and three CheckBox-es one for each color.
After a research on the Web I found this Dynamic LINQ library made available by Scott Guthrie. Since the most recent example/tutorial I found is from 2009, I was wondering whether this library is actually good (and maintained) or not.
In the latter case is jQuery the best way to implement such functionality?
You can solve it by building the needed predicate expressions dynamically, using purely .NET framework.
See code sample below. Depending on the criteria, this will filter on multiple properties. I've used IQuerable because this will enable both In-Memory as remote scenario's such as Entity Framework. If you're going with Entity Framework, you could also just build an EntitySQL string dynamically. I expect that will perform better.
There is a small portion of reflection involved (GetProperty). But this could be improved by performing caching inside the BuildPredicate method.
public class Item
{
public string Color { get; set; }
public int Value { get; set; }
public string Category { get; set; }
}
class Program
{
static void Main(string[] args)
{
var list = new List<Item>()
{
new Item (){ Category = "Big", Color = "Blue", Value = 5 },
new Item (){ Category = "Small", Color = "Red", Value = 5 },
new Item (){ Category = "Big", Color = "Green", Value = 6 },
};
var criteria = new Dictionary<string, object>();
criteria["Category"] = "Big";
criteria["Value"] = 5;
var query = DoDynamicWhere(list.AsQueryable(), criteria);
var result = query.ToList();
}
static IQueryable<T> DoDynamicWhere<T>(IQueryable<T> list, Dictionary<string, object> criteria)
{
var temp = list;
//create a predicate for each supplied criterium and filter on it.
foreach (var key in criteria.Keys)
{
temp = temp.Where(BuildPredicate<T>(key, criteria[key]));
}
return temp;
}
//Create i.<prop> == <value> dynamically
static Expression<Func<TType, bool>> BuildPredicate<TType>(string property, object value)
{
var itemParameter = Expression.Parameter(typeof(TType), "i");
var expression = Expression.Lambda<Func<TType, bool>>(
Expression.Equal(
Expression.MakeMemberAccess(
itemParameter,
typeof(TType).GetProperty(property)),
Expression.Constant(value)
),
itemParameter);
return expression;
}
}
I don't really get why would you need the Dynamic LINQ here? Are the item properties not known at compile-time? If you can access a given item properties by name, eg. var prop = myitem['Color'], you don't need Dynamic LINQ.
It depends on how you render the results. There is a lot of ways to achieve the desired behavior, in general:
Fully client-side. If you do everything client-side (fetching data, rendering, paging) - jQuery would be the best way to go.
Server-side + client-side. If you render results on the server, you may add HTML attributes (for each property) to each search result markup and filter those client-side. The only problem in this case can be paging (if you do paging server-side, you will be able to filter the current page only)
Fully server-side. Post the form with search parameters and narrow down the search results using LINQ - match the existing items' properties with form values.
EDIT
If I were you (and would need to filter results server-side), I'd do something like:
var filtered = myItems.Where(i => i.Properties.Match(formValues))
where Match is an extension method that checks if a given list of properties matches provided values. Simple as this - no Dynamic LINQ needed.
EDIT 2
Do you need to map the LINQ query to the database query (LINQ to SQL)? That would complicate things a bit, but is still doable by chaining multiple .Where(...) clauses. Just loop over the filter properties and add .Where(...) to the query from previous iteration.
you may have a look at PredicateBuilder from the author of C# 4.0 in a Nutshell
As already pointed out by #Piotr Szmyd probabbly you don't need dynamic Linq. Iterating over all properties of T doesn'require dynamic linq. Dynamic Linq is mainly usefull to build complete queries on the client side and send it in string format to the server.
However now, it become obsolete, since Mvc 4 supports client side queries through Api Controllers returning an IQueryable.
If you just need to iterate over all properties of T you can do it with reflection and by building the LambdaExpressions that will compose the filtering criterion. You can do it with the static methods of the Expression class.
By using such static methods you can build dynamically expressions like m => m.Name= "Nick" with a couple instructions...than you put in and them...done you get and expression you can apply to an exixting IQueryable
LINQ implementation still has not changed so there should be no problem using the dynamic LINQ library. It simply creates LINQ expressions from strings.
You can use AJAX to call action methods that run the LINQ query and return JSON data. JQuery would populate HTML from the returned data.

Entity Framework 4 - List<T> Order By based on T's children's property

I have the following code -
public void LoadAllContacts()
{
var db = new ContextDB();
var contacts = db.LocalContacts.ToList();
grdItems.DataSource = contacts.OrderBy(x => x.Areas.OrderBy(y => y.Name));
grdItems.DataBind();
}
I'm trying to sort the list of the contacts according to the area name that is contained within each contact. When I tried the above, I get "At least one object must implement IComparable.". Is there an easy way instead of writing a custom IComparer?
Thanks!
try this:
public void LoadAllContacts()
{
var db = new ContextDB();
var contacts = db.LocalContacts.ToList();
grdItems.DataSource = contacts.OrderBy(x => x.Areas.OrderBy(y => y.Name).First().Name);
grdItems.DataBind();
}
this will order the contacts by the first area name, after ordering the areas by name.
Hope this helps :)
Edit: fixed error in code. (.First().Name)
I was in a discussion with #AbdouMoumen but in the end I thought I'd provide my own answer :-)
His answer works, but there two performance issues in this code (both in the answer as in the original question).
First, the code loads ALL contacts in the db. This may or may not be a problem, but in general I would recommend NOT to do this. Many modern controls support paging/filtering out of the box, so you'd be better off supplying an not-yet-evaluated IQueryable<T> instead of List<T>. If however you need everything in memory, you should delay the ToList to the last possible moment.
Second, in AbdouMoumen's answer, there is a so-called 'SELECT N+1' problem. Entity Framework will by default use lazy loading to fetch additional properties. I.e. the Areas property will not be fetched from the database until it's accessed. In this case this will happen in the controls 'for loop', while it's ordering the result set by name.
Open up SQL Server Profiler to see what I mean: you will see a SELECT statement for all the contacts, and an additional SELECT statement for each contact that fetches the Areas for that contact.
A much better solution would be the following:
public void LoadAllContacts()
{
using (var db = new ContextDB())
{
// note: no ToList() yet, just defining the query
var contactsQuery = db.LocalContacts
.OrderBy(x => x.Areas
.OrderBy(y => y.Name)
.First().Name);
// fetch all the contacts, correctly ordered in the DB
grdItems.DataSource = contactsQuery.ToList();
grdItems.DataBind();
}
}
Is it one to one relation (Contact->Area)?
if yeah then try the following :
public partial class Contact
{
public string AreaName
{
get
{
if (this.Area != null)
return this.Area.Name;
return string.Empty;
}
}
}
then
grdItems.DataSource = contacts.OrderBy(x => x.AreaName);

Find items is SSRS by Id

How do you find items in SSRS by ID? I tried to use the id returned by another find result, a new guid to string and small random string all of which return the same error:
The ID field has a value that is not valid. ---> Microsoft.ReportingServices.Diagnostics.Utilities.InvalidElementException: The ID field has a value that is not valid.
Here is the code:
var request = new FindItemsRequest
{
Conditions = new[] { new SearchCondition { Name = "ID", Value = "test"} },
Folder = "/"
};
return _ssrsService
.FindItems(request)
.Items
I'm using SSRS 2005.
Pretty sure this can't be done through the SSRS service. Ended up finding all objects then using LINQ to filter down to the ID I need.
The MS documentation on the FindItems method says:
Applications that use FindItems typically accept user input for specific properties and property values. The searchable properties are Name, Description, CreatedBy, CreationDate, ModifiedBy, and ModifiedDate. The items that are returned are only those for which a user has Read Properties permission.

Using DataObjectTypeName in DataObjectSource

The functionality I am trying to use is:
- Create a ObjectDataSource for selection and updating controls on a web page (User Control).
- Use the DataObjectTypeName to have an object created that would send the data to an UpdateMethod.
- Before the values are populated in the DataObjectTypeName’s object, I would like to pre-populate the object so the unused items in the class are not defaulted to zeros and empty strings without me knowing whether the zero or default string was set by the user or by the application.
I cannot find a way to pre-populate the values (this was an issue back in 2006 with framework 2.0). One might ask “Why would anyone need to pre-populate the object?”. The simple answer is: I want to be able to randomly place controls on different User Controls and not have to be concerned with which UpdateMethod needs to handle which fields of an object.
For Example, let’s say I have a class (that reflects a SQL Table) that includes the fields: FirstName, LastName, Address, City, State, Zip. I may want to give the user the option to change the FirstName and LastName and not even see the Address, City, State, Zip (or vice-versa). I do not want to create two UpdateMethods where one handled FirstName and LastName and the other method handles the other fields. I am working with a Class of some 40+ columns from multiple tables and I may want some fields on one screen and not another and decide later to change those fields from one screen to another (which breaks my UpdateMethods without me knowing).
I hope I explained my issue well enough.
Thanks
This is hardly a solution to the problem, but it's my best stab at it.
I have a GridView with its DataSourceID set to an ObjectDataSource.
Whenever a row is updated, I want the property values in the object to be selectively updated - that is - only updated if they appear as columns in the GridView.
I've created the following extension:
public static class GridViewExtensions
{
public static void EnableLimitUpdateToGridViewColumns(this GridView gridView)
{
_gridView = gridView;
if (_gridView.DataSourceObject != null)
{
((ObjectDataSource)_gridView.DataSourceObject)
.Updating += new ObjectDataSourceMethodEventHandler(objectDataSource_Updating);
}
}
private static GridView _gridView;
private static void objectDataSource_Updating(object sender, ObjectDataSourceMethodEventArgs e)
{
var newObject = ((object)e.InputParameters[0]);
var oldObjects = ((ObjectDataSource)_gridView.DataSourceObject).Select().Cast<object>();
Type type = oldObjects.First().GetType();
object oldObject = null;
foreach (var obj in oldObjects)
{
if (type.GetProperty(_gridView.DataKeyNames.First()).GetValue(obj, null).ToString() ==
type.GetProperty(_gridView.DataKeyNames.First()).GetValue(newObject, null).ToString())
{
oldObject = obj;
break;
}
}
if (oldObject == null) return;
var dynamicColumns = _gridView.Columns.OfType<DynamicField>();
foreach (var property in type.GetProperties())
{
if (dynamicColumns.Where(c => c.DataField == property.Name).Count() == 0)
{
property.SetValue(newObject, property.GetValue(oldObject, null), null);
}
}
}
}
And in the Page_Init event of my page, I apply it to the GridView, like so:
protected void Page_Init()
{
GridView1.EnableLimitUpdateToGridViewColumns();
}
This is working well for me at the moment.
You could probably apply similar logic to other controls, e.g. ListView or DetailsView.
I'm currently scratching my head to think of a way this can be done in a rendering-agnostic manner - i.e. without having to know about the rendering control being used.
I hope this ends up as a normal feature of the GridView or ObjectDataSource control rather than having to hack it.

How do you model form changes under Spring MVC?

Say you're writing a web page for fruit vendors using Spring MVC's SimpleFormController, version 2.5.6. On this page the vendor can do simple things like change their name or their address. They can also change their inventory based on a drop down list filled with present inventory selections.
When this drop down list selection changes, the entire form changes to match the inventory of what has been selected. So one stock selection may have bananas and pears, another may have melons, blueberries and grapefruit.
Inside each inventory selection is a input field that needs to be propagated back to the database, for the sake of this example let's say that the user enters the number of fruit.
The way this is modeled in the database is that each Stock name is stored in a table, which has a one to many relationship with the contents of each stock, which would be the type of fruit in this example. Then the type of fruit has a one to many relationship with the quantity the vendor selects. Stock name and the type of fruit in each stock are stored in the database and are unchangeable by the user, with the connected fruit quantity table being editable.
My question is, how do you model the form described above in Spring MVC?
I've tried overriding the isFormChangeRequest and onFormChange to facilitate the form change, but I think I may be misunderstanding the intent of these methods. When I change my backing command object the next time the page is post it tries to bind the request into the form, which breaks if you adjust the size of the Stock array (say from 3 to 2, it will try and bind into the 3rd value, even if it is empty).
If you have a limited amount of different stocks, you can use different handler mappings for each one with a different backing model:
#RequestMapping(params="stock=example1")
ModelAndView handleExample1(#ModelAttribute("stock") ApplesOrangesPears stockObject)
#RequestMapping(params="stock=example2")
ModelAndView handleExample2(#ModelAttribute("stock") BananasPotatos stockObject)
But I guess that is not the case, there are a lot of different stock types and they are dynamic. In that case you can register custom property editor (#InitBinder), and determine dynamically the actual type of the backing object for the inventory, then validate, and convert to or from it explicitly.
What I ended up doing is firing a JavaScript event when the selection in the drop down is changed. This JavaScript (seen below) generates a URL based on the selection of the drop down and uses a location.replace to go to the new URL, which causes the controller to generate a new form.
Using this method over overriding the isFormChangeRequest and onFormChange has allowed me to avoid binding errors caused by left over post data.
function changeUrl(selectionValue) {
var param = getParams();
param["dropdownselection"] = selectionValue;
window.location.replace(getBaseUrl() + buildQueryString(param));
}
//taken from http://javascript.about.com/library/blqs1.htm
function getParams() {
var qsParm = new Array();
var query = window.location.search.substring(1);
var parms = query.split('&');
for (var i = 0; i < parms.length; i++) {
var pos = parms[i].indexOf('=');
if (pos > 0) {
var key = parms[i].substring(0,pos);
var val = parms[i].substring(pos+1);
qsParm[key] = val;
}
}
return qsParm;
}
function getBaseUrl() {
var url = document.location.toString();
if (url.indexOf('?') != -1) {
url = url.substring(0, url.indexOf('?'));
}
return url;
}
function buildQueryString(param) {
var queryString = "?";
for (var key in param) {
queryString += key + "=" + param[key] + "&";
}
//remove last "&"
return queryString.substring(0,queryString.length - 1);
}

Resources