CRM 2011: Получение сущности с помощью Javascript

Я работаю над некоторыми настройками CRM 2011 Online, и мне нужно получить объект с помощью javascript.

Сущность, которая мне нужна, будет основана на значении идентификатора другого поля (сущности контакта) - этот идентификатор контакта я могу получить нормально.

Сущность, которую я хочу, - это настраиваемая сущность. Может быть несколько совпадений на основе идентификатора контакта, поэтому я просто хочу получить первое в списке (порядок не важен)

Пока что я рассмотрел несколько способов сделать это ...

  • OData - мне не удалось найти достаточно примеров того, какие выражения запросов я могу создавать, также я не знаю, как это сделать для настраиваемых сущностей.

  • FetchXML - я могу создать хороший запрос FetchXML, используя встроенный «расширенный поиск», и был бы рад вызвать его из javascript, если кто-нибудь может помочь? Я нашел один многообещающий ответ здесь, но я не мог видеть, как устанавливаются данные возврата "результатов" (функция Service.Fetch)

  • Запрос SOAP. Первое, что я попробовал, - это метод, аналогичный тому, что я мог бы сделать в CRM 4, но он, похоже, не работает. Хотя запрос выполняется, мои данные результатов кажутся пустыми. Это все, для чего у меня есть код, поэтому, если кто-то может обнаружить проблему с приведенным ниже кодом, это было бы здорово.

РЕДАКТИРОВАТЬ: я обнаружил некоторые избыточные данные запроса (я удалил открывающие теги ссылки, но оставил закрывающие теги) - после удаления этого я теперь получаю данные результата XML ... однако предложение where, похоже, не применить (просто получить список всех сущностей)

    var xml = "<?xml version='1.0' encoding='utf-8'?>" + 
    "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">" + 
    GenerateAuthenticationHeader() +
    "<soap:Body>" + 
    "<RetrieveMultiple xmlns=\"http://schemas.microsoft.com/crm/2007/WebServices\">" + 
    "<query xmlns:q1=\"http://schemas.microsoft.com/crm/2006/Query\" xsi:type=\"q1:QueryExpression\">" + 
    "<q1:EntityName>new_vehicle</q1:EntityName>" + 
    "<q1:ColumnSet xsi:type='q1:ColumnSet'>" + 
    "<q1:Attributes>" + 
    "<q1:Attribute>new_vehicleid</q1:Attribute>" +
    "<q1:Attribute>new_primarydriver</q1:Attribute>" +
    "<q1:Attribute>statuscode</q1:Attribute>" +
    "<q1:Attribute>new_registration</q1:Attribute>" +
    "</q1:Attributes>" + 
    "</q1:ColumnSet>" + 
    "<q1:Distinct>false</q1:Distinct>" + 

    "<q1:Conditions>" + 

                     "<q1:Condition>" +
                     "<q1:AttributeName>new_primarydriver</q1:AttributeName>" +
    "<q1:Operator>Equal</q1:Operator>" +
    "<q1:Values>" +
    "<q1:Value xmlns:q2='http://microsoft.com/wsdl/types/' xsi:type='q2:guid'>" +
    customerID +
    "</q1:Value></q1:Values></q1:Condition>" + 

    "</q1:Conditions>" +

    "</query></RetrieveMultiple>" +
    "</soap:Body></soap:Envelope>";


    var xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");

    xmlHttpRequest.Open("POST", "/mscrmservices/2007/CrmService.asmx", false);
    xmlHttpRequest.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/crm/2007/WebServices/RetrieveMultiple");
    xmlHttpRequest.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
    xmlHttpRequest.setRequestHeader("Content-Length", xml.length);
    xmlHttpRequest.send(xml);

    var result = xmlHttpRequest.responseXML.xml;
    var doc = new ActiveXObject("MSXML2.DOMDocument");
    doc.async = false;
    doc.loadXML(result);

    var id = doc.selectSingleNode("//new_vehicleid");
    var registration = doc.selectSingleNode("//new_registration");

    if(id == null)
       return null;

    var vehicle = new Array();
                     value[0] = new Object();
                     value[0].id = id;
                     value[0].name = registration;
                     value[0].entityType = "new_vehicle";

    return vehicle;

Извините за большой пост кода, но надеюсь, что кто-то, кто лучше понимает, может помочь


person musefan    schedule 24.10.2011    source источник


Ответы (1)


Во-первых, спасибо GlennFerrieLive за его ответ. Примеры, которые я нашел с помощью Dynamics CRM 2011 SDK (ну просто one в частности) действительно помогло, а включенный парсер JSON идеально подошел для этой работы!

Я публикую этот ответ, чтобы дать полный пример того, как я это сделал, с некоторыми важными комментариями, на которые следует обратить внимание, которые могут быть не так очевидны из примеров SDK.


Получить выбранное значение идентификатора из поля поиска

Целью моей задачи было использование javascript для установки поля поиска на основе выбранных данных другого объекта поиска. Устанавливаемая сущность - «new_vehicle», а сущность для запроса - «customer».

Первая задача - получить значение идентификатора поля поиска контактов ...

var customerItem = Xrm.Page.getAttribute("customerid").getValue();
var customerID = customerItem[0].id;

Запрос объекта с использованием идентификатора

Далее идет часть, в которой я использовал значение идентификатора клиента, чтобы найти транспортное средство, которое в настоящее время назначено им (сущность, которую я хочу использовать для установки поля поиска).

Первая проблема, которую я обнаружил, заключалась в том, что при запросе с помощью OData значение идентификатора не работает с фигурными скобками {}, поэтому их необходимо удалить ...

customerID = customerID.replace('{', '').replace('}', '');

Далее мы получаем oDataPath ...

var oDataPath = Xrm.Page.context.getServerUrl() + "/xrmservices/2011/organizationdata.svc";

Затем мы можем построить запрос OData ...

var filter = "/new_vehicleSet?" +
  "$select=new_vehicleId,new_Registration" + 
  "&$filter=new_PrimaryDriver/Id eq (guid'" + customerID + "')" + 
  "&$orderby=new_LastAllocationDate desc" + 
  "&$top=1";

ПРИМЕЧАНИЕ. Здесь следует отметить несколько важных моментов ...

  1. При использовании значения guid вы должны явно указать, что это guid, используя (guid'xxx')
  2. При фильтрации по поисковому объекту (например, new_PrimaryDriver) вы должны добавить значение в запрос (например, Id) - это приведет к new_PrimaryDriver / Id

После настройки запроса мы можем запросить данные следующим образом ...

var retrieveRecordsReq = new XMLHttpRequest();
retrieveRecordsReq.open("GET", oDataPath + filter, true);
retrieveRecordsReq.setRequestHeader("Accept", "application/json");
retrieveRecordsReq.setRequestHeader("Content-Type", "application/json; charset=utf-8");
retrieveRecordsReq.onreadystatechange = function () {
    if (this.readyState == 4) {
       if (this.status == 200) {
           var retrievedRecords = JSON.parse(retrieveRecordsReq.responseText).d;
           if(retrievedRecords.results.length > 0)
           {
               var vehicle = retrievedRecords.results[0];
               SetLookup("new_replacedvehicle", vehicle.new_vehicleId, vehicle.new_Registration, "new_vehicle");
           }
       }
    }
};
retrieveRecordsReq.send();

Обратите внимание, что это асинхронный вызов, и функция onreadystatechange будет обработана по завершении, в этой функции мы делаем несколько проверок, чтобы увидеть, было ли это успешным, и мы анализируем полученные данные JSON - функция JSON.Parse была включена внизу этого сообщения (но доступно из SDK )


Настройка поля поиска с использованием объекта, запрошенного выше

Другая функция, на которую стоит обратить внимание, - это SetLookup, которая представляет собой простую вспомогательную функцию, которую я добавил для установки поля поиска. Это так ...

function SetLookup(fieldName, idValue, textValue, typeValue)
{
    var value = new Array();
    value[0] = new Object();
    value[0].id = idValue;
    value[0].name = textValue;
    value[0].typename = typeValue;

    Xrm.Page.getAttribute(fieldName).setValue(value);
}

Функция синтаксического анализа JSON

Это вспомогательная функция JSON, которая использовалась в приведенном выше коде (JSON.parse), вставлена ​​так, как она была найдена в SDK ...

if (!this.JSON) { this.JSON = {}; } (function () { function f(n) { return n < 10 ? '0' + n : n; } if (typeof Date.prototype.toJSON !== 'function') { Date.prototype.toJSON = function (key) { return isFinite(this.valueOf()) ? this.getUTCFullYear() + '-' + f(this.getUTCMonth() + 1) + '-' + f(this.getUTCDate()) + 'T' + f(this.getUTCHours()) + ':' + f(this.getUTCMinutes()) + ':' + f(this.getUTCSeconds()) + 'Z' : null; }; String.prototype.toJSON = Number.prototype.toJSON = Boolean.prototype.toJSON = function (key) { return this.valueOf(); }; } var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, gap, indent, meta = { '\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"': '\\"', '\\': '\\\\' }, rep; function quote(string) { escapable.lastIndex = 0; return escapable.test(string) ? '"' + string.replace(escapable, function (a) { var c = meta[a]; return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); }) + '"' : '"' + string + '"'; } function str(key, holder) { var i, k, v, length, mind = gap, partial, value = holder[key]; if (value && typeof value === 'object' && typeof value.toJSON === 'function') { value = value.toJSON(key); } if (typeof rep === 'function') { value = rep.call(holder, key, value); } switch (typeof value) { case 'string': return quote(value); case 'number': return isFinite(value) ? String(value) : 'null'; case 'boolean': case 'null': return String(value); case 'object': if (!value) { return 'null'; } gap += indent; partial = []; if (Object.prototype.toString.apply(value) === '[object Array]') { length = value.length; for (i = 0; i < length; i += 1) { partial[i] = str(i, value) || 'null'; } v = partial.length === 0 ? '[]' : gap ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' : '[' + partial.join(',') + ']'; gap = mind; return v; } if (rep && typeof rep === 'object') { length = rep.length; for (i = 0; i < length; i += 1) { k = rep[i]; if (typeof k === 'string') { v = str(k, value); if (v) { partial.push(quote(k) + (gap ? ': ' : ':') + v); } } } } else { for (k in value) { if (Object.hasOwnProperty.call(value, k)) { v = str(k, value); if (v) { partial.push(quote(k) + (gap ? ': ' : ':') + v); } } } } v = partial.length === 0 ? '{}' : gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' : '{' + partial.join(',') + '}'; gap = mind; return v; } } if (typeof JSON.stringify !== 'function') { JSON.stringify = function (value, replacer, space) { var i; gap = ''; indent = ''; if (typeof space === 'number') { for (i = 0; i < space; i += 1) { indent += ' '; } } else if (typeof space === 'string') { indent = space; } rep = replacer; if (replacer && typeof replacer !== 'function' && (typeof replacer !== 'object' || typeof replacer.length !== 'number')) { throw new Error('JSON.stringify'); } return str('', { '': value }); }; } if (typeof JSON.parse !== 'function') { JSON.parse = function (text, reviver) { var j; function walk(holder, key) { var k, v, value = holder[key]; if (value && typeof value === 'object') { for (k in value) { if (Object.hasOwnProperty.call(value, k)) { v = walk(value, k); if (v !== undefined) { value[k] = v; } else { delete value[k]; } } } } return reviver.call(holder, key, value); } text = String(text); cx.lastIndex = 0; if (cx.test(text)) { text = text.replace(cx, function (a) { return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); }); } if (/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { j = eval('(' + text + ')'); return typeof reviver === 'function' ? walk({ '': j }, '') : j; } throw new SyntaxError('JSON.parse'); }; } } ());
person musefan    schedule 25.10.2011
comment
CRM Dynamics ?, не покупайте его, если вам нужны настройки: D Простое требование, сложная реализация ... - person Legends; 25.09.2016