AXForum  
Вернуться   AXForum > Microsoft Dynamics CRM > Dynamics CRM: Разработка
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 14.02.2008, 01:33   #1  
Черничкин Станислав is offline
Черничкин Станислав
Злыдни
Аватар для Черничкин Станислав
Злыдни
 
53 / 18 (1) ++
Регистрация: 16.10.2007
Адрес: Екатеринбург
crmForm.IsDirty зохватит всех!
Оказывается чтение crmForm.IsDirty в crm 3 занимает кучу времени (правда эта "куча" хорошо заметна только на PIII и ниже). Долго же я "оптимизировал" вызов веб метода, перед тем как допёр, что причина тормозов в чтении IsDirty
Старый 15.02.2008, 07:32   #2  
ShurikEv is offline
ShurikEv
CRM
 
213 / 28 (1) +++
Регистрация: 25.04.2006
Адрес: г. Новосибирск
Не могу это проверить, т.к. по-близости PIII и тем более ниже нет :-) Но этот факт кажется мне очень странным... У меня есть эта проверка кое-где, но коиенты еще не разу не жаловались на тормаза, хотя у них и PIII и ниже встречается. Хотя может быть я не прав, надо поспрашивать. Если удасться выяснить, то обязательно отпишусь.
Вдруг, это только единичный случай :-) Т.к. я не представляю, на что куча времени может тратиться. Максимум что там может происходить - проход по всем полям формы и проверка на IsDirty. Ну это JS. Хотя компы и не быстрые, но эта процедура на JS должна выполниться достаточно быстро.
Старый 15.02.2008, 08:28   #3  
tatra is offline
tatra
Участник
 
229 / 11 (1) +
Регистрация: 21.09.2007
Адрес: Самара
Извините за любопытсвто - а что это за свойство?
Старый 15.02.2008, 09:01   #4  
Артем Enot Грунин is offline
Артем Enot Грунин
Moderator
Аватар для Артем Enot Грунин
MCBMSS
Злыдни
Most Valuable Professional
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,912 / 623 (28) +++++++
Регистрация: 16.08.2007
Адрес: Пермь!
Записей в блоге: 151
2 tatra: Это проверка на то, что значение поля изменилось. Аналогичное свойство есть и у формы.
2 Черничкин Станислав: Расскажу вам одну историю. Я как-то раз писал программу, выполнение которой занимало кучу времени. Так вот чтобы убедится, что она не повисла, на длительный обработчик я повесил окошко с прогресс баром - это такой контрол, который показывает процент завершенности. Так вот, я долго оптимизировал код, а скорость работы совершенно не увеличивалась, что меня ужасно бесило. В конце концов я начал отключать модули один за другим, чтобы определить узкое место, пока не остался чистый цикл for вообще без всяких операций. Я сперва тоже долго негодовал, что это ОН , оказывается, тормозит мою программу!!! Но потом дошло, что я слишком часто перерисовываю прогресс бар и это он хавает все ресурсы.
После того как я от него избавился программа стала работать мгновенно. Маловероятно, что причина в том о чем вы говорите. Контролы мелкомягких помимо текущего хранят и исходное значение (original value). Вы можите не использовать IsDirty, а проводить проверку самостоятельно.
__________________
http://fixrm.wordpress.com, снятие/наведение порчи. Быстро, дорого, гарантия.

MS Certified Dirty Magic Professional

Последний раз редактировалось Артем Enot Грунин; 15.02.2008 в 09:03.
Старый 18.02.2008, 11:00   #5  
Черничкин Станислав is offline
Черничкин Станислав
Злыдни
Аватар для Черничкин Станислав
Злыдни
 
53 / 18 (1) ++
Регистрация: 16.10.2007
Адрес: Екатеринбург
2: enot poloskun:
Если убрать SerializeIsDirty запросы на PIII начинают выполняться аж по пол секунды. Развлекайся:

function _GetErrorMessage(exception)
{
return (exception != null) && (exception.description != null) ? exception.description : exception;
}
function _IsNullOrEmpty(str)
{
return (str == null) || (str == "");
}
function _ParseBool(str)
{
return !_IsNullOrEmpty(str) && ((str.toLowerCase() == "true") || (str == "1"));
}
function _ThrowArgumentNullException(paramName)
{
var error = new Object();
error.description = "Значение не может быть неопределенным.";
if (paramName != null)
error.description += "\nИмя параметра: " + paramName;
throw error;
}
function _ThrowInvalidOperationException(message)
{
var error = new Object();
error.description = message;
throw error;
}
function ExtenderMethodInvoker(extender, methodInfo)
{
if (extender == null)
_ThrowArgumentNullException("extender");
return (function()
{
try
{
extender.InvokeExtenderMethod(methodInfo);
}
catch (e)
{
alert(_GetErrorMessage(e));
if (event != null)
event.returnValue = false;
}
});
}
function Extender()
{
this.ExtensionSiteAddress = "http://crm3.local:7010/"
this.ExtensionServiceNamespace = "urn:schemas-infosyst-biz:mscrm-extend";
this.CrmServiceNamespace = "http://schemas.microsoft.com/crm/2006/WebServices";
this.FormExtensionsFolder = "FormExtenders/"
this.ExtensionService = this.ExtensionSiteAddress + this.FormExtensionsFolder + crmForm.ObjectTypeName + ".asmx";
this.AttributeValueNull = function(attributeNode)
{
if (attributeNode == null)
_ThrowArgumentNullException("attributeNode");
return attributeNode.getAttribute("IsNull") == 'true';
}

this.DeserializeAttribute = function(attributeNode, attributeInfo)
{
if (attributeNode == null)
_ThrowArgumentNullException("attributeNode");
if (attributeInfo == null)
_ThrowArgumentNullException("attributeInfo");
switch (attributeInfo.Type)
{
case "String":
crmForm.all[attributeInfo.Name].DataValue = attributeNode.text;
break;
case "Float":
case "Currency":
if (this.AttributeValueNull(attributeNode))
crmForm.all[attributeInfo.Name].DataValue = null;
else
crmForm.all[attributeInfo.Name].DataValue = parseFloat(attributeNode.text);
break;
case "Integer":
case "Duration":
case "Picklist":
case "StatusReason":
case "State":
if (this.AttributeValueNull(attributeNode))
crmForm.all[attributeInfo.Name].DataValue = null;
else
crmForm.all[attributeInfo.Name].DataValue = parseInt(attributeNode.text);
break;
case "Customer":
case "Regarding":
case "Lookup":
case "PartyList":
if (this.AttributeValueNull(attributeNode))
crmForm.all[attributeInfo.Name].DataValue = null;
else
{
var lookup = new Object();
lookup.id = attributeNode.text;
var typeName = attributeNode.getAttribute("type");
lookup.typename = typeName != null ? typeName : attributeInfo.ReferencedType;
lookup.name = attributeNode.getAttribute("name");
var bullShit = new Array();
bullShit[0] = lookup;
crmForm.all[attributeInfo.Name].DataValue = bullShit;
}
break;
default:
_ThrowInvalidOperationException("Десериализация аттрибутов типа " + attributeInfo.Type + " не поддерживается.");
break;
}
}
this.DeserializeAttributeInfos = function(node)
{
if (node == null)
_ThrowArgumentNullException("node");
var attributeNodeList = node.selectNodes("attribute");
var attributeInfos = new Array();
for (var i = 0; i < attributeNodeList.length; i++)
{
var attributeNode = attributeNodeList.item(i);
var attributeInfo = new Object();
attributeInfo.Name = attributeNode.getAttribute("name");
attributeInfo.ReferencedType = attributeNode.getAttribute("referencedType");
attributeInfo.Type = attributeNode.getAttribute("type");
attributeInfos[i] = attributeInfo;
}
return attributeInfos;
}
this.DeserializeEntity = function(node, attributeInfos)
{
if (attributeInfos == null)
_ThrowArgumentNullException("attributeInfos");
if (node != null)
{
for (var i = 0; i < attributeInfos.length; i++)
{
var attributeInfo = attributeInfos[i];
try
{
var attributeNode = node.selectSingleNode(attributeInfo.Name);
if (attributeNode != null)
this.DeserializeAttribute(attributeNode, attributeInfo);
}
catch (e)
{
alert("Ошибка десериализации атрибута " + attributeInfo.Name + ": " + _GetErrorMessage(e) + "\nДесериализация будет продолжена.");
}
}
}
}
this.InvokeExtenderMethod = function(methodInfo)
{
if (methodInfo == null)
_ThrowArgumentNullException("methodInfo");
var request =
'<' + methodInfo.ExtenderMethod + ' xmlns="' + this.ExtensionServiceNamespace + '" >' +
'<formType>' + crmForm.FormType + '</formType>' +
'<entity xmlns="' + this.CrmServiceNamespace + '">' + this.SerializeEntity(methodInfo.InAttributes) + '</entity>';
if (methodInfo.SerializeIsDirty)
request += '<isDirty>' + crmForm.IsDirty + '</isDirty>';
request += '</' + methodInfo.ExtenderMethod + '>';
var message = this.WrapSoapMessage(request);
var messageResponse = this.InvokeSoapMethod(this.ExtensionService, message);
var response = this.ParseSoapResult(messageResponse, methodInfo.ExtenderMethod + "Response", this.ExtensionServiceNamespace);
this.DeserializeEntity(response.selectSingleNode(methodInfo.ResultNodeName), methodInfo.OutAttributes);
}
this.InvokeSoapMethod = function(service, message)
{
if (service == null)
_ThrowArgumentNullException("service");
if (message == null)
_ThrowArgumentNullException("message");
var xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");
xmlHttpRequest.Open("POST", service, false);
xmlHttpRequest.setRequestHeader("Content-Type", "application/soap+xml; charset=utf-8");
xmlHttpRequest.setRequestHeader("Content-Length", message.length);
xmlHttpRequest.send(message);
var responseText = xmlHttpRequest.responseText;
var responseDocument = new ActiveXObject("MSXML2.DOMDocument");
if (!responseDocument.loadXML(responseText))
{
var errorString =
(xmlHttpRequest.status != 200 ? "Ошибка выполнения WEB запроса " + xmlHttpRequest.status + ": " + xmlHttpRequest.statusText + "\n" : "Ошибка разбора ответного сообщения.\n") +
(_IsNullOrEmpty(responseText) ? "Ответное сообщение пусто." :
"Ответ сервера:\n" +
"---------------------------\n" +
responseText +
"\n---------------------------");
_ThrowInvalidOperationException(errorString);
}
return responseDocument;
}

this.ParseSoapResult = function(resultXml, exceptedElementName, exceptedElementNamespace)
{
if (resultXml == null)
_ThrowArgumentNullException("resultXml");
var namespaces = 'xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:extend="' + this.ExtensionServiceNamespace + '"';
if (exceptedElementNamespace != null)
namespaces += ' xmlns:result="' + exceptedElementNamespace + '"';
resultXml.setProperty("SelectionNamespaces", namespaces);
var faultNode = resultXml.selectSingleNode("/soap:Envelope/soap:Body/soap:Fault");
if (faultNode != null)
{
var friendlyMessageNode = faultNode.selectSingleNode('soapetail/extend:friendlyMessage');
if (friendlyMessageNode != null)
_ThrowInvalidOperationException(friendlyMessageNode.text);
else
{
var faultCodeNode = faultNode.selectSingleNode('soap:Code');
var faultStringNode = faultNode.selectSingleNode('soap:Reason');
var faultDetailNode = faultNode.selectSingleNode('soapetail');

var errorString = "Ошибка выполнения WEB запроса.\n" +
(faultCodeNode != null ? "Код ошибки: " + faultCodeNode.text + "\n" : "") +
(faultStringNode != null ? "Описание: " + faultStringNode.text + "\n" : "") +
(faultDetailNode != null ?
"Детальная информация: \n" +
"---------------------------\n" +
faultDetailNode.xml +
"\n---------------------------\n" : "");
_ThrowInvalidOperationException(errorString);
}
}
if (exceptedElementName != null)
{
var exceptedElement = resultXml.selectSingleNode((exceptedElementNamespace != null ? "/soap:Envelope/soap:Body/result:" : "/soap:Envelope/soap:Body/") + exceptedElementName);
if (exceptedElement == null)
{
var errorString1 = "Ошибка выполнения WEB запроса.\n" +
"Корневой элемент сообщения не найден либо не соответсвует ожидаемому значению.\n" +
"Ожидаемое имя корневого элемента: " + exceptedElementName + "\n" +
(exceptedElementNamespace != null ? "Ожидаемое пространство имен корневого элемента: " + exceptedElementNamespace + "\n" : "") +
"Текст сообщения: \n" +
"---------------------------\n" +
resultXml.xml +
"\n---------------------------\n";
_ThrowInvalidOperationException(errorString1);
}
return exceptedElement;
}
else
return resultXml.selectSingleNode("/soap:Envelope/soap:Body/*");
}
this.SerializeEntity = function(attributeInfos)
{
if (attributeInfos == null)
_ThrowArgumentNullException("attributeInfos");
var entityData = "";
for (var i = 0; i < attributeInfos.length; i++)
{
var attributeInfo = attributeInfos[i];
if (attributeInfo.Type == "Key")
{
if (!_IsNullOrEmpty(crmForm.ObjectId))
entityData += '<' + attributeInfo.Name + '>' + crmForm.ObjectId + '</' + attributeInfo.Name + '>';
}
else
{
var dataValue = crmForm.all[attributeInfo.Name].DataValue;
switch (attributeInfo.Type)
{
case "String":
if (dataValue != null)
entityData += '<' + attributeInfo.Name + '>' + dataValue + '</' + attributeInfo.Name + '>';
break;
case "Integer":
case "Duration":
case "DateTime":
case "Float":
case "Currency":
case "Boolean":
entityData += '<' + attributeInfo.Name;
if (dataValue == null)
entityData += ' IsNull="true" />';
else
entityData += '>' + dataValue + '</' + attributeInfo.Name + '>';
break;
case "Picklist":
case "StatusReason":
case "State":
entityData += '<' + attributeInfo.Name;
if (dataValue == null)
entityData += ' IsNull="true" />';
else
entityData += ' name="' + crmForm.all[attributeInfo.Name].SelectedText + '">' + dataValue + '</' + attributeInfo.Name + '>';
break;
case "Customer":
case "Regarding":
case "Lookup":
case "PartyList":
entityData += '<' + attributeInfo.Name;
if (dataValue == null)
entityData += ' IsNull="true" />';
else
entityData += ' name="' + dataValue[0].name + '" type="' + dataValue[0].typename + '">' + dataValue[0].id + '</' + attributeInfo.Name + '>';
break;
default:
_ThrowInvalidOperationException("Сериализация аттрибутов типа " + attributeInfo.Type + " не поддерживается");
break;
}
}
}
return entityData;
}
this.WrapSoapMessage = function(message)
{
if (message == null)
_ThrowArgumentNullException("message");
return '<?xml version="1.0" encoding="utf-8"?><soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope"><soap12:Body>' + message + '</soap12:Body></soap12:Envelope>';
}

var extenderInfoRequest = '<getExtenderInfo xmlns="' + this.ExtensionServiceNamespace + '" />';
extenderInfoRequestMessage = this.WrapSoapMessage(extenderInfoRequest);
var extenderInfoResponseMessage = this.InvokeSoapMethod(this.ExtensionService, extenderInfoRequestMessage);
var extenderInfoResponse = this.ParseSoapResult(extenderInfoResponseMessage, "getExtenderInfoResponse", this.ExtensionServiceNamespace);
var methodNodeList = extenderInfoResponse.selectNodes("formExtenderInfo/methods/method");
for (var methodNode = methodNodeList.nextNode(); methodNode != null; methodNode = methodNodeList.nextNode())
{ //TODO: добавить механизм со
var methodInfo = new Object();
methodInfo.ExtenderMethod = methodNode.getAttribute("extenderMethod");
methodInfo.ResultNodeName = methodNode.getAttribute("resultNodeName");
methodInfo.SerializeIsDirty = _ParseBool(methodNode.getAttribute("serializeIsDirty"));
methodInfo.TargetElement = methodNode.getAttribute("targetElement");
methodInfo.TargetEvent = methodNode.getAttribute("targetEvent");
methodInfo.TargetMethod = methodNode.getAttribute("targetMethod");
methodInfo.InAttributes = this.DeserializeAttributeInfos(methodNode.selectSingleNode("inAttributes"));
methodInfo.OutAttributes = this.DeserializeAttributeInfos(methodNode.selectSingleNode("outAttributes"));
var entenderMethodInvoker = new ExtenderMethodInvoker(this, methodInfo);
if (!_IsNullOrEmpty(methodInfo.TargetElement))
{
var targetElement = crmForm.all[methodInfo.TargetElement];
if (!_IsNullOrEmpty(methodInfo.TargetEvent))
targetElement.attachEvent(methodInfo.TargetEvent, entenderMethodInvoker);
if (!_IsNullOrEmpty(methodInfo.TargetMethod))
targetElement[methodInfo.TargetMethod] = entenderMethodInvoker;
}
else
{
if (!_IsNullOrEmpty(methodInfo.TargetEvent))
if (methodInfo.TargetEvent == "onload")
this.OnLoad = entenderMethodInvoker;
else
crmForm.attachEvent(methodInfo.TargetEvent, entenderMethodInvoker);
if (!_IsNullOrEmpty(methodInfo.TargetMethod))
crmForm[methodInfo.TargetMethod] = entenderMethodInvoker;
}
}
}
var extender = new Extender();
if (extender.OnLoad != null)
extender.OnLoad();

ШУТКА!!!
На самом деле IsDirty вполне может подтормаживать, потому-что не факт, что он выполняется локально. Возможно он на каждой проверке лезет в базу и сравнивает поля на форме с полями в базе (такое поведение разумно, это один из паттернов оптимистической блокировки). Мне лень разбираться, я просто добавил if и скорость подскочила в несколько раз.
Старый 18.02.2008, 12:27   #6  
Артем Enot Грунин is offline
Артем Enot Грунин
Moderator
Аватар для Артем Enot Грунин
MCBMSS
Злыдни
Most Valuable Professional
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,912 / 623 (28) +++++++
Регистрация: 16.08.2007
Адрес: Пермь!
Записей в блоге: 151
А я уже хотел возмущаться против таких наворотов на в скриптах формы.
Тоже думал об этом, но мне отчего-то сомнительно, что IsDirty лезет в базу. Нелогично это, что ли. Одним словом пофиг - проблема снята, все довольны.
__________________
http://fixrm.wordpress.com, снятие/наведение порчи. Быстро, дорого, гарантия.

MS Certified Dirty Magic Professional
Старый 18.02.2008, 14:57   #7  
Черничкин Станислав is offline
Черничкин Станислав
Злыдни
Аватар для Черничкин Станислав
Злыдни
 
53 / 18 (1) ++
Регистрация: 16.10.2007
Адрес: Екатеринбург
Вот смотри: В 16.00 я открываю форму организации "Рога и Копыта" и начинаю в нее смотреть. В 16.05 ты открываешь ту же форму, меняешь значение поля "название" на "Копыта и Рога" и в 16.06 сохраняешь ее. В 16.10 я решаю, что с карточкой все в порядке и жму на кнопку "сохранить" (вот она, проверка IsDirty). Вопрос: если я снова открою форму в 16.30 и увижу там "Копыта и Рога" и дату последнего изменения 16.06, при том, что я точно буду знать, что в 16.10 там было "Рога и Копыта" и я нажал кнопку "сохранить", как внедренец мне объяснит "пачему название не сохраняецо?". Вывод: IsDirty должна сравнивать значение на форме со значением в базе.З.Ы. java скрипт с формы, только никому об этом не рассказывай
Старый 18.02.2008, 15:25   #8  
ShurikEv is offline
ShurikEv
CRM
 
213 / 28 (1) +++
Регистрация: 25.04.2006
Адрес: г. Новосибирск
Провел с коллегой эксперимент
Ну что я могу сказать по этому поводу... Для чистоты экспериментов даже открыл Fiddler, чтобы отлавливать все запросы-ответы сервера. В общем, я убедился, что при сохранении нет запроса к БД как такового. Выяснил (ну как мне кажется), что при сохранении формы, идёт проверка на то какие поля менялись (у поля тоже есть свойство isDirty), если значение поля менялось, то это значение и записывается в БД (это всё на стороне сервера, это же АСП ;-) ). Поэтому ваш случай в рамках этого подхода Если бы оба меняли название, то в БД сохранилось бы последнее введеное А так при при нажатии на "Сохранить" в БД записываются только измененные значения полей.
Старый 18.02.2008, 16:20   #9  
Артем Enot Грунин is offline
Артем Enot Грунин
Moderator
Аватар для Артем Enot Грунин
MCBMSS
Злыдни
Most Valuable Professional
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,912 / 623 (28) +++++++
Регистрация: 16.08.2007
Адрес: Пермь!
Записей в блоге: 151
Что и требовалось доказать! Осталось только понять фигли оно тормозит? Лично у меня нет - проверял.
__________________
http://fixrm.wordpress.com, снятие/наведение порчи. Быстро, дорого, гарантия.

MS Certified Dirty Magic Professional
Старый 18.02.2008, 17:53   #10  
Черничкин Станислав is offline
Черничкин Станислав
Злыдни
Аватар для Черничкин Станислав
Злыдни
 
53 / 18 (1) ++
Регистрация: 16.10.2007
Адрес: Екатеринбург
2 Енот Полоскун
Запусти этот скрипт и почувствуй гнев праведных (не советую запускать на машине ниже Core 2, гнев быдет невыносимым
var d = new Date();
var donkey = "";
for (var i = 0; i < 100; i++)
{
if (crmForm.IsDirty)
donkey += "donkey";
}
alert(new Date() - d);
d = new Date();
var jennet = "";
for (var i = 0; i < 100; i++)
{
if (i == i)
jennet += "jennet";
}
alert(new Date() - d);

честно говоря а очень ли оно интересно, почему тормозит? все равно ускорить не сможем. лично я не хочу тратить время на выяснение причины.
Старый 19.02.2008, 08:10   #11  
ShurikEv is offline
ShurikEv
CRM
 
213 / 28 (1) +++
Регистрация: 25.04.2006
Адрес: г. Новосибирск
Запустил. Выдало на:
1. Core 2 - 500 и 0
2. на Р-4 2ГГц - 1650 и 0
Тут задержка опять же ясна. Только зачем по 100 раз проверять форму? Да, на проверку тратится время, по моим меркам, не смертельное.
Вот насчет ускорить не можем... Проблему надо локализовывать. У нас тоже были проблемы: пользователи жаловались что у них всё медленно работает. Пеняли на сервер и обработки на форме, оказалось что дело в сети :-) Сеть починили, всё залетало.
"лично я не хочу тратить время на выяснение причины" - ваше право
 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Сохраняется ли форма когда IsDirty == false? Черничкин Станислав Dynamics CRM: Разработка 2 13.12.2007 21:20
Ошибка на всех страничках glad Dynamics CRM: Администрирование 5 24.07.2006 10:36
Поменял подразделение у всех пользователей в CRM cruzo Dynamics CRM: Администрирование 2 29.09.2005 17:32

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 09:32.