11.04.2011, 11:35 | #1 |
Участник
|
SOAP-запрос для получения списка записей N:N
Здравствуйте. У меня возник такой вопрос. Можно ли при помощи SOAP-запроса получить список записей, связанных отношением N;N с данной?
|
|
11.04.2011, 11:43 | #2 |
Moderator
|
Без проблем. Можно использовать как fetch так и retrive запросы. N:N - это, фактически два отношения 1:N с промежуточной сущностью, которая называется объект пересечения. Имя этого объекта можно посмотреть в настройках связи. Объект пересечения содержит пары идентификаторов связанных сущностей, так что вам, фактически нужно выбрать все экземпляры объекта пересечения, которые ссылаются на вашу сущность. Так вы получите список записей второго объекта, связанного с ней.
__________________
http://fixrm.wordpress.com, снятие/наведение порчи. Быстро, дорого, гарантия. MS Certified Dirty Magic Professional Последний раз редактировалось Артем Enot Грунин; 11.04.2011 в 11:45. |
|
11.04.2011, 11:48 | #3 |
Moderator
|
Вот нашел у себя в коде функцию:
Код: var oTypeThis = crmForm.ObjectTypeCode; var oTypeThisName = crmForm.ObjectTypeName; var oTypeAssociated = Product; var oTypeAssociatedName = "product"; var oAssociationName = "new_productsForLead"; var oAssociationRecordName = "new_productsforlead"; function getAssociatedRecordsIds() { var oFetchXML = "<fetch mapping='logical'>" + "<entity name='" + oAssociationRecordName + "'>" + "<attribute name='" + oTypeAssociatedName + "id'/>" + "<filter type='and'>" + "<condition attribute='" + oTypeThisName + "id' operator='eq' value='" + crmForm.ObjectId + "'/>" + "</filter>" + "</entity>" + "</fetch>"; oFetchXML = oFetchXML.replace(/</g, '<'); oFetchXML = oFetchXML.replace(/>/g, '>'); var oSOAP = "<?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>" + "<Fetch xmlns='http://schemas.microsoft.com/crm/2007/WebServices'>" + "<fetchXml>" + oFetchXML + "</fetchXml>" + "</Fetch>"+ "</soap:Body>"+ "</soap:Envelope>"; var oXmlHttp = new ActiveXObject("Msxml2.XMLHTTP"); oXmlHttp.Open("POST", "/mscrmservices/2007/CrmService.asmx", false); oXmlHttp.setRequestHeader("SOAPAction","http://schemas.microsoft.com/crm/2007/WebServices/Fetch"); oXmlHttp.setRequestHeader("Content-Type", "text/xml; charset=utf-8"); oXmlHttp.setRequestHeader("Content-Length", oSOAP.length); oXmlHttp.send(oSOAP); var oResponseText = oXmlHttp.responseXML.text; var oXmlDoc = new ActiveXObject("Microsoft.XMLDOM"); oXmlDoc.async = false; oXmlDoc.loadXML(oResponseText); var results = oXmlDoc.getElementsByTagName(oTypeAssociatedName + "id"); var associatedRecordsIds = new Array(results.length); for (var i = 0; i < results.length; i++) { associatedRecordsIds[i] = results[i].text; } return associatedRecordsIds; }
__________________
http://fixrm.wordpress.com, снятие/наведение порчи. Быстро, дорого, гарантия. MS Certified Dirty Magic Professional |
|
|
За это сообщение автора поблагодарили: Skyway (1). |
11.04.2011, 12:20 | #4 |
Участник
|
Спасибо! Как раз то что нужно. Все заработало с первого раза.
|
|
11.04.2011, 12:25 | #5 |
Moderator
|
Пожалуйста, вот оригинальный пост: http://www.axforum.info/forums/blog.php?b=46, возможно вам пригодится еще что-то из изложенного функционала.
__________________
http://fixrm.wordpress.com, снятие/наведение порчи. Быстро, дорого, гарантия. MS Certified Dirty Magic Professional |
|
|
За это сообщение автора поблагодарили: Skyway (1). |
18.04.2011, 09:01 | #6 |
Участник
|
Возник еще один вопрос по схожей теме. Нужно написать FetchXML - запрос, который возвращает только свои записи, если роль текущего пользователя "Сотрудник", и все записи в противном случае. При этом определение принадлежности записи пользователю происходит на основе значения поля new_person, а не на основе ownerid. Возможно ли написать такой запрос?
Последний раз редактировалось Skyway; 18.04.2011 в 09:29. |
|
18.04.2011, 11:09 | #7 |
Moderator
|
Да, но для этого потребуется 2-3 запроса.
1. Получить идентификатор пользователя (WhoAmI). 2. Вычитать роли пользователя с нужным названием 3. Сделать выводы и построить нужный запрос.
__________________
http://fixrm.wordpress.com, снятие/наведение порчи. Быстро, дорого, гарантия. MS Certified Dirty Magic Professional |
|
18.04.2011, 11:37 | #8 |
Чайный пьяница
|
Цитата:
__________________
Эмо разработчик, сначала пишу код, потом плачу над его несовершенством. Подписывайтесь на мой блог, twitter и YouTube канал. Пользуйтесь моим Ultimate Workflow Toolkit |
|
18.04.2011, 11:47 | #9 |
Участник
|
Вообще, FetchXML мне нужен для создания представления, то есть javascript, как я понимаю, там нельзя использовать.Представление будет создаваться при помощи плагина, который описан здесь: http://mmcrm.ru/?p=1531
Можно ли использовать несколько запросов при помощи данного способа? |
|
18.04.2011, 11:56 | #10 |
Moderator
|
Верно! Я почему-то подумал, что для нестандартного поля в пункте 3 EqualUserId не сработает.
__________________
http://fixrm.wordpress.com, снятие/наведение порчи. Быстро, дорого, гарантия. MS Certified Dirty Magic Professional |
|
18.04.2011, 12:01 | #11 |
Moderator
|
Цитата:
Сообщение от Skyway
Вообще, FetchXML мне нужен для создания представления, то есть javascript, как я понимаю, там нельзя использовать.Представление будет создаваться при помощи плагина, который описан здесь: http://mmcrm.ru/?p=1531
Можно ли использовать несколько запросов при помощи данного способа?
__________________
http://fixrm.wordpress.com, снятие/наведение порчи. Быстро, дорого, гарантия. MS Certified Dirty Magic Professional |
|
19.04.2011, 16:31 | #12 |
Участник
|
Ну да, приложение, это была описка)
Пытаюсь тут разобраться с плагином. Хочу чтобы выполнялся хотябы простой запрос. Создал новое представление, в описании написал new_business_trip.all, поменял плагин следующим образом: X++: using System; using Microsoft.Crm.Sdk; using Microsoft.Crm.SdkTypeProxy; using System.Data.SqlClient; using Microsoft.Crm.Sdk.Query; namespace CustomQueryAPI { public class QueryFetchPlugin : IPlugin { private string connectionString; IPluginExecutionContext pluginContext; public QueryFetchPlugin(string unsecure, string secure) { //"Data Source=CRMDEV;Initial Catalog=ICS_MSCRM;Integrated Security=SSPI" connectionString = secure; } public void Execute(IPluginExecutionContext context) { this.pluginContext = context; DynamicEntity query = (DynamicEntity)pluginContext.OutputParameters[ParameterName.BusinessEntity]; string api = (string)query.Properties["description"]; if (String.IsNullOrEmpty(api)) return; // Для систематизации и удобства наращивания api группируются в наборы ClassAPI.MetodAPI string[] paths = api.Split(new string[] { "." }, StringSplitOptions.RemoveEmptyEntries); if (paths.Length < 2) return; string className = paths[0]; string methodName = paths[1]; string myFetch = String.Empty; switch (className) { case "New_business_trip": myFetch = retrieveBusinessTrip(methodName); break; } if (myFetch != null) query.Properties["fetchxml"] = myFetch; } private string queryExpressionToFetch(QueryBase query) { QueryExpressionToFetchXmlRequest request = new QueryExpressionToFetchXmlRequest(); request.Query = query; ICrmService service = this.pluginContext.CreateCrmService(true); QueryExpressionToFetchXmlResponse responce = (QueryExpressionToFetchXmlResponse)service.Execute(request); return responce.FetchXml; } private string sqlToFetch(string entity, string primarykey, string sql) { string fetchPattern = @"<fetch version=""1.0"" output-format=""xml-platform"" mapping=""logical"" distinct=""false""> <entity name=""{0}""> <attribute name=""{1}""/> <filter type=""and""> <condition attribute=""{1}"" operator=""in""> {2} </condition> </filter> </entity> </fetch>"; string filterValues = String.Empty; using (SqlConnection sqlConnection = new SqlConnection(this.connectionString)) { sqlConnection.Open(); SqlCommand cmd = new SqlCommand(sql, sqlConnection); SqlDataReader reader = cmd.ExecuteReader(); try { while (reader.Read()) { string id = ((Guid)reader[0]).ToString(); filterValues += "<value>" + id + "</value>\n"; } } finally { reader.Close(); } } return String.Format(fetchPattern, entity, primarykey, filterValues); } private string retrieveBusinessTrip(string methodName) { string fetch = String.Empty; switch (methodName) { case "all": string sqlQuery = "SELECT new_business_tripid FROM new_business_trip Where new_name like 'г%'"; fetch = sqlToFetch("new_business_trip", "new_business_tripid", sqlQuery); break; } return fetch; } } } Но почему-то ничего не происходит, такое впечатление что плагин не работает. |
|
19.04.2011, 16:42 | #13 |
Moderator
|
Отлаживаться пробовали? При регистрации плагина указывалась строка соединения в параметре secure?
__________________
http://fixrm.wordpress.com, снятие/наведение порчи. Быстро, дорого, гарантия. MS Certified Dirty Magic Professional |
|
21.04.2011, 09:42 | #14 |
Участник
|
Да, строку соединения указал. Отлаживать пытался, с этим какая-то проблема - отладчик не вызывается о_О
За все время моих попыток он вызвался единственный раз, и сработало исключение на этой строчке: DynamicEntity query = (DynamicEntity)pluginContext.OutputParameters[ParameterName.BusinessEntity]; Исключение по поводу неправильности ключа (Invalid или Null, я точно не запомнил). Непонятна логика срабатывания плагина(или отладчика). Как я понял, вызов должен происходить при просмотре любого представления? |
|
21.04.2011, 16:33 | #15 |
Участник
|
В результате как я понял происходит что-то вроде кеширования, то есть плагин начинает работать не сразу после регистрации, а по прошествии достаточно продолжительного количества времени. Кто-нибудь сталкивался с этим? iisreset не помогает.
Ошибка следующая: "The given key not present in the dictionary" в этой строке: DynamicEntity query = (DynamicEntity)pluginContext.OutputParameters[ParameterName.BusinessEntity]; |
|
21.04.2011, 22:34 | #16 |
Moderator
|
Вы знаете, я бы не выложил бы код, если бы не был уверен, что он работает. Возможно вы все же указали какие-то другие параметры при регистрации, или зарегистрировали плагин не на то событие? Я как раз сегодня читал лекцию по плагинам и мы с группой смотрели как в Output параметрах возвращается объект который должно вернуть событие. В случае Retrive это должен быть объект BusinessEntity. Ума не приложу, почему его может не быть в этом событии. Пожалуйста проверьте еще раз все ли правильно вы настроили.
__________________
http://fixrm.wordpress.com, снятие/наведение порчи. Быстро, дорого, гарантия. MS Certified Dirty Magic Professional |
|
21.04.2011, 22:50 | #17 |
Участник
|
Цитата:
У меня отладка Вашего плагина и плагина Артема срабатывает при каждом вызове. Проблем со срабатывание не наблюдаются. Посмею предположить что Вы регистрируете плагин в базе. Если да попробуйте на диске. Цитата:
По поводу ошибки.
У меня OutputParameters пустой. Поэтому мы и получаем ошибку. (Проверял на разных сущностях системных, не системных) P. S. Возможно после установке очередного ролапа эта возможность просто пропала.
__________________
Читайте SDK!!! |
|
|
За это сообщение автора поблагодарили: Skyway (1). |
21.04.2011, 23:06 | #18 |
Участник
|
Переместив плагин на PostRetrieve код заработал как положено.
__________________
Читайте SDK!!! |
|
21.04.2011, 23:54 | #19 |
Moderator
|
Ну, мог и опечататься Вообще пре-событие происходит до обработки внутри системной транзакции, так что пока система не вкурила что ее дурят, нужно выполнить нашу подмену. Либо действительно несовпадение версий, либо я что-то напутал.
__________________
http://fixrm.wordpress.com, снятие/наведение порчи. Быстро, дорого, гарантия. MS Certified Dirty Magic Professional Последний раз редактировалось Артем Enot Грунин; 21.04.2011 в 23:59. |
|