Crm 2016 Create option set indicates all entities - dynamics-crm

I have created an entity, and i want a option for show all entities in create form, how can i do this?
Something like option set in process form:

Here's some JavaScript code to retrieve all Entities
Here are some key points about the code
Using Underscore (_) which is available on the top frame, but may not be available in other contexts
Only selecting ($select) the EntityTypeCode and DisplayName properties
Applying a range of filters to try to reduce the number of results. Filters include the following
Must not be a Business Process Flow entity
Must not be an Intersect entity (i.e. the join table in an N:N relationship)
Must not be an Activity
Must not be an ActivityParty
Must be available in Advanced Find
Must be able to trigger workflow
Code:
var underscore = top["_"];
var entityMetadata = (function(_) {
return { retrieve: queryMetadata };
function buildEntityList(data)
{
var entities = _.chain(data.entities)
.map(function(entity) {
return {
"Name": entity.DisplayName.UserLocalizedLabel.Label,
"ETC": entity.ObjectTypeCode
};
})
.sortBy("Name")
.value();
return entities;
}
function queryMetadata()
{
var select = "$select=DisplayName,ObjectTypeCode";
var filter = "$filter="
filter += "IsBPFEntity eq false";
filter += " and IsIntersect eq false";
filter += " and IsActivity eq false";
filter += " and IsActivityParty eq false";
filter += " and CanTriggerWorkflow eq true";
filter += " and IsValidForAdvancedFind eq true";
var p = Xrm.WebApi.retrieveMultipleRecords("EntityDefinitions", "?" + select + "&" + filter).then(buildEntityList);
return p;
}
})(underscore);
This code returns a promise with all Entities matching the above criteria. Here's how to call it, and write the results to the browser console:
entityMetadata.retrieve().then(console.log);
This outputs all the Display Names and Entity Type Codes to the console like so:
Other answers on StackOverflow show how to build a select control with options so I won't include that here.

You can either create a static option set containing all the entities, or you can create a custom web resource with an option set that dynamically populates onLoad, then after the user selects an option store the entity name on a field on the form. The second option is typically what I do.

You can query the metadata using the WebApi. From there you can retrieve a list of entities and every fields they contain.
https://msdn.microsoft.com/en-us/library/mt607522.aspx

Related

Need help getting the data validation criteria from "list from a range" in an apps script so I can cycle through those values

I want to get the data validation criteria from "list from a range" in an apps script so I can cycle through those values. For example, in cell A5 I have data validation set up, with "criteria" being "List from a range" and the corresponding range being "'Grade K Class MTSS Profile'!B2:AH2". I want it to return "'Grade K Class MTSS Profile'!B2:AH2" so I can cycle through this range and do something with the cells contained in that range.
This is the code I have so far:
function onOpen(e) {
SpreadsheetApp.getUi()
.createMenu('MTSS Tools')
.addItem('Save All Student Reports', 'saveAllStudentReports')
.addToUi();
}
function saveAllStudentReports() {
var cell = SpreadsheetApp.getActive().getRange('A4');
var rule = cell.getDataValidation();
var ui = SpreadsheetApp.getUi();
if (rule != null) {
var criteria = rule.getCriteriaType();
var args = rule.getCriteriaValues();
ui.alert("Has rule");
ui.alert('The data validation rule is ' + criteria + args);
}
else
{
ui.alert("NO rule");
}
}
However, I'm not getting the actual range. Ideas? Thank you very much!
As you can see in the documentation:
getCriteriaValues returns:
Object[] — an array of arguments appropriate to the rule's criteria type; the number of arguments and their type match the corresponding require...() method of the DataValidation class
So args is a Range object, which means all methods from the Range class can be used, like getA1Notation:
ui.alert('The data validation rule is ' + criteria + ' ' + args[0].getA1Notation()

Dynamic Linq on DataTable error: no Field or Property in DataRow, c#

I have some errors using Linq on DataTable and I couldn't figure it out how to solve it. I have to admit that i am pretty new to Linq and I searched the forum and Internet and couldn't figure it out. hope you can help.
I have a DataTable called campaign with three columns: ID (int), Product (string), Channel (string). The DataTable is already filled with data. I am trying to select a subset of the campaign records which satisfied the conditions selected by the end user. For example, the user want to list only if the Product is either 'EWH' or 'HEC'. The selection criteria is dynaically determined by the end user.
I have the following C# code:
private void btnClick()
{
IEnumerable<DataRow> query =
from zz in campaign.AsEnumerable()
orderby zz.Field<string>("ID")
select zz;
string whereClause = "zz.Field<string>(\"Product\") in ('EWH','HEC')";
query = query.Where(whereClause);
DataTable sublist = query.CopyToDataTable<DataRow>();
}
But it gives me an error on line: query = query.Where(whereClause), saying
No property or field 'zz' exists in type 'DataRow'".
If I changed to:
string whereClause = "Product in ('EWH','HEC')"; it will say:
No property or field 'Product' exists in type 'DataRow'
Can anyone help me on how to solve this problem? I feel it could be a pretty simple syntax change, but I just don't know at this time.
First, this line has an error
orderby zz.Field<string>("ID")
because as you said, your ID column is of type int.
Second, you need to learn LINQ query syntax. Forget about strings, the same way you used from, orderby, select in the query, you can also use where and many other operators. Also you'll need to learn the equivalent LINQ constructs for SQL-ish things, like for instance IN (...) is mapped to Enumerable.Contains etc.
With all that being said, here is your query
var productFilter = new[] { "EWH", "HEC" };
var query =
from zz in campaign.AsEnumerable()
where productFilter.Contains(zz.Field<string>("Product"))
orderby zz.Field<int>("ID")
select zz;
Update As per your comment, if you want to make this dynamic, then you need to switch to lambda syntax. Multiple and criteria can be composed by chaining multiple Where clauses like this
List<string> productFilter = ...; // coming from outside
List<string> channelFilter = ...; // coming from outside
var query = campaign.AsEnumerable();
// Apply filters if needed
if (productFilter != null && productFilter.Count > 0)
query = query.Where(zz => productFilter.Contains(zz.Field<string>("Product")));
if (channelFilter != null && channelFilter.Count > 0)
query = query.Where(zz => channelFilter.Contains(zz.Field<string>("Channel")));
// Once finished with filtering, do the ordering
query = query.OrderBy(zz => zz.Field<int>("ID"));

Get all rows not filtered from jqGrid

I have local data in a grid. How can I get all of the rows or IDs that are not removed after a user uses the filter toolbar? I need to get all filtered rows, regardless of pagination.
For example, say I begin with 50 rows in the grid. The user uses the filter toolbar and the set of rows decreases to 10 rows. How can I get those ten rows?
There are no direct way to get the information which you need. Internally jqGrid uses $.jgrid.from to filter local data. The main code which uses $.jgrid.from in inside of addLocalData. To get results which you need without studying all the code I suggest to use the fact that all filtered data will be returned by select method of $.jgrid.from (see the line of code). My suggestion is to catch the data before the data will be cut to the page size.
To do this I suggest to use sub-classing: overwriting of the method select method of $.jgrid.from. I demonstrate the technique in the examples created for the answer and this one.
In your case the code will be
var oldFrom = $.jgrid.from,
lastSelected;
$.jgrid.from = function (source, initalQuery) {
var result = oldFrom.call(this, source, initalQuery),
old_select = result.select;
result.select = function (f) {
lastSelected = old_select.call(this, f);
return lastSelected;
};
return result;
};
Now the variable lastSelected will save the array of elements which are results of the last sorting or filtering operation. Because $.jgrid.from is global the data are not connected to the grid. If you have more as one grid on the page it will be uncomfortable. One can fix the small disadvantage with the following line in the code of loadComplate of every grid:
loadComplete: function () {
this.p.lastSelected = lastSelected; // set this.p.lastSelected
}
In the way we introduce new jqGrid parameter lastSelected which will have close structure as data parameter, but will hold only last filtered data.
The following code will display the ids of filtered data in alert message
$("#getIds").click(function () {
var filteredData = $grid.jqGrid('getGridParam', 'lastSelected'), i, n, ids = [],
idName = $grid.jqGrid('getGridParam', 'localReader').id;
if (filteredData) {
for (i = 0, n = filteredData.length; i < n; i++) {
ids.push(filteredData[i][idName]);
}
alert("tolal number of filtered data: " + n + "\n" +
"ids of filtered data:\n" + ids.join(', '));
}
});
I used localReader.id parameter because property name used for local data are typically id or _id_. The _id_ will be used in case of data loaded from the server if one uses loadonce: true option.
The demo demonstrate the approach. If one filter for example only the data from FedEx and then clicks on "Show Ids" button one will see information about all filtered and not only about the data displayed on the current page:
UPDATED: free jqGrid provides new lastSelectedData option. See the demo in the list of demos.
You colud use afterSearch option of the search toolbar:
var filteredIDs = new Array(); //Global variable
$("#"+gridId).jqGrid("filterToolbar", { stringResult:true, searchOnEnter:false,
afterSearch:function(){
filteredIDs = $("#"+gridId).getDataIDs();
}
});
If you want to get the filtered rows instead the filtered IDs, use getRowData() instead of getDataIDs().
All, I found another answer which is far easier to include
loadComplete: function (gridData) {
var isSearchPerformed = $grid.getGridParam("postData")._search;
if (isSearchPerformed) {
$("#spanFilterTotal").text(gridData.records);
}
All you want is below:
$.each($grid.getRowData(), function( index, value ) {
a.push(value["COLUMN_NAME"]); //Get the selected data you want
});

Get IGrouping data in Repeater ItemDataBound

I am wanting to group news articles by year in a repeater. The format would be:
2010
list of articles
2011
List of Articles
My access layer returns a flat list of news articles, specifically List. Therefore, I am grouping them and binding them to the Repeater as follows:
events = DAL.GetEvents();
var groupedNewsList = from e in events
group e by e.StoryDate.Year
into g
select new {
Year = g.Key
, Events = g
};
rptEvents.DataSource = groupedNewsList;
rptEvents.DataBind();
The problem is trying to get the List from within the ItemDataBound event. So far, I have the following:
var data = e.Item.DataItem;
System.Type type = data.GetType();
// getting the year works fine
string year = (string)type.GetProperty("Year").GetValue(data, null).ToString();
// this returns something, but I can't access any properties. I need to get
//access to the contained List<News>
var newsList = type.GetProperty("Events").GetValue(data, null);
Any ideas?
Thanks in advance!
You don't have a List<News> - you just have a grouping. If you want a List<News>, you'll need to change your query, e.g.
var groupedNewsList = from e in events
group e by e.StoryDate.Year into g
select new { Year = g.Key, Events = g.ToList() };
Note that if you're using C# 4 you could do reflection rather more easily using dynamic typing:
dynamic data = e.Item.DataItem;
string year = data.Year.ToString();
List<News> newsList = data.Events;
Alternatively, you could avoid using an anonymous type in the first place - create your own GroupedNewsList type with Year and Events properties, populate that in your query, and then cast to it in your event handler.
The "sender" object in the ItemDataBound event is the repeater -- use it to get to the data-source. If the data-source has been grouped before binding, you can compare the current value to the previous value & hide the year-field if they are equal. Like this:
MyObject item = (MyObject)item.DataItem;
Repeater repeater = (sender as Repeater);
List<MyObject> items = repeater.DataSource as List<MyObject>;
Label lblGrouping = (Label)item.FindControl("lblGrouping");
if (item.ItemIndex == 0 || item.DateField.Year != items[item.ItemIndex - 1].DateField.Year) {
lblGrouping.Text = item.DateField.Year.ToString();
}
This worked for me, as I used a table with each row being one item, and the left-most column contained the "lblGrouping" control.

How do I set a parameter to a list of values in a BIRT report?

I have a DataSet with a query like this:
select s.name, w.week_ending, w.sales
from store s, weekly_sales_summary w
where s.id=w.store_id and s.id = ?
I would like to modify the query to allow me to specify a list of store IDs, like:
select s.name, w.week_ending, w.sales
from store s, weekly_sales_summary w
where s.id=w.store_id and s.id IN (?)
How do I accomplish this in BIRT? What kind of parameter do I need to specify?
The easy part is the report parameter: set the display type to be List Box, then check the Allow Multiple Values option.
Now the hard part: unfortunately, you can't bind a multi-value report parameter to a dataset parameter (at least, not in version 3.2, which is what I'm using). There's a posting on the BIRT World blog here:
http://birtworld.blogspot.com/2009/03/birt-multi-select-statements.html
that describes how to use a code plug-in to bind multi-select report parameters to a report dataset.
Unfortunately, when I tried it, it didn't work. If you can get it to work, that's the method I would recommend; if you can't, then the alternative would be to modify the dataset's queryText, to insert all the values from the report parameter into the query at the appropriate point. Assuming s.id is numeric, here's a function that can be pasted into the beforeOpen event script for the datasource:
function fnMultiValParamSql ( pmParameterName, pmSubstituteString, pmQueryText )
{
strParamValsSelected=reportContext.getParameterValue(pmParameterName);
strSelectedValues="";
for (var varCounter=0;varCounter<strParamValsSelected.length;varCounter++)
{
strSelectedValues += strParamValsSelected[varCounter].toString()+",";
}
strSelectedValues = strSelectedValues.substring(0,strSelectedValues.length-1);
return pmQueryText.replace(pmSubstituteString,strSelectedValues);
}
which can then be called from the beforeOpen event script for the dataset, like this:
this.queryText = fnMultiValParamSql ( "rpID", "0 /*rpID*/", this.queryText );
assuming that your report parameter is called rpID. You will need to amend your query to look like this:
select s.name, w.week_ending, w.sales
from store s, weekly_sales_summary w
where s.id=w.store_id and s.id IN (0 /*rpID*/)
The 0 is included in the script so that the query script is valid at design time, and the dataset values will bind correctly to the report; at runtime, this hard-coded 0 will be removed.
However, this approach is potentially very dangerous, as it could make you vulnerable to SQL Injection attacks: http://en.wikipedia.org/wiki/SQL_injection , as demonstrated here: http://xkcd.com/327/ .
In the case of purely numeric values selected from a predefined picklist, a SQL injection attack should not be possible; however, the same approach is vulnerable where freeform entry strings for the parameter are allowed.
FYI: the BIRT World article should work (I wrote it) but that was an earlier solution to the problem.
We have created an open source plugin that you can add to BIRT that has a much cleaner solution to this problem. The Bind Parameters function in the birt-functions-lib provides a simple way to do multi-selects from multi-value parameters.
If you are still interested have a look at the birt-functions-lib project on Eclipse Labs.
Here's another one. Based on some hints I found elsewhere and extended to preserve the number of parameters in your data set SQL. This solution works with a JavaScript function that you call at OnBeforeOpen of the data set:
prepare(this);
function prepare(dataSet) {
while (dataSet.queryText.indexOf("#IN?")>=0) {
dataSet.queryText = dataSet.queryText.replace(
"#XYZ?",
"('"+params["products"].value.join("','")+"') or ?=0"
);
}
}
In your query, replace occurrences of (?) with #XYZ?. The method above makes sure that
the query has the actual values and still a parameter (so that the dataset editor and preview doesn't complain).
Note: Beware of SQL injection, e.g. by not allowing string values
I created a more general solution, which handles optional/required parameters behaviour too. When parameter is not required and user doesn't select any value, the IN-clause gets disabled. It also allows the user to select both real values and null value.
In report initialize script I add this code:
/** Fullfill IN-clause in a data set query,
* using a List box report parameter.
* Placeholder must be the parentheses after IN keyword with wathever you want inside.
* If required is false then the whole IN-clause in the query
* must be surrounded by parentheses.
* dataType and required refers to the parameter, they must be passed,
* but should be better to find a way to retrieve them inside this function
* (given parameter name).
*/
function fulfillInClause(dataSet, placeholder, param, dataType, required) {
if (dataSet.queryText.indexOf(placeholder)>=0) {
var paramValue = params[param].value;
var emptyParam = (paramValue==null || paramValue.length<=0);
//build the list of possible values
// paramValue==null check in ternary operators
// will prevent exceptions when user doesn't select any value
// (it will not affect the query if param is optional,
// while we will never arrive here if it is required)
var replacement = " (";
if (dataType == "string")
replacement += (emptyParam ? "''" : createList(paramValue, ",", "'", "varchar(10)") );
else if (dataType == "integer")
replacement += (emptyParam ? "0" : createList(paramValue, ",", "" , "int" ) );
else
//TODO implement more cases
return;
replacement += ") ";
//if param is not required and user doesn't select any value for it
//then nullify the IN clause with an always-true clause
if (!required && emptyParam)
replacement += " or 0=0 ";
//put replacement in the query
dataSet.queryText = dataSet.queryText.replace( placeholder, replacement );
//DEBUG
params["debug" + dataSet.name + "Query"]=dataSet.queryText;
}
}
/** Create a string list of array values,
* separated by separator and each of them surrounded by a pair surrounders
*/
function createList(array, separator, surrounder, sqlDataType){
var result = "";
for(var i=0; i<array.length; i++) {
if(result.length>0)
result += separator;
if(array[i]!=null)
result += surrounder + array[i] + surrounder;
else
result += "cast(null as " + sqlDataType + ")";
}
return result;
}
Usage example
In dataset query put your special IN-clause:
select F1, F2
from T1
where F3='Bubi'
and ( F4 in (''/*?customers*/) )
In beforeOpen script of the dataset with the IN-clause write:
fulfillInClause(this, "(''/*?customers*/)", "customers", "string", false);
Note that I used a placeholder which allows the query to run also before the replacement (eg. it has quotes as F4 is a varchar). You can build a placeholder that fits your case.

Resources