| | | 1 | | using Microsoft.Crm.Sdk.Messages; |
| | | 2 | | using Microsoft.Xrm.Sdk; |
| | | 3 | | using Microsoft.Xrm.Sdk.Messages; |
| | | 4 | | using Microsoft.Xrm.Sdk.Query; |
| | | 5 | | using System; |
| | | 6 | | using System.Collections.Generic; |
| | | 7 | | using System.Linq; |
| | | 8 | | using System.ServiceModel; |
| | | 9 | | using System.Xml.Linq; |
| | | 10 | | |
| | | 11 | | namespace FakeXrmEasy.FakeMessageExecutors |
| | | 12 | | { |
| | | 13 | | public class ExecuteFetchRequestExecutor : IFakeMessageExecutor |
| | | 14 | | { |
| | 4295 | 15 | | private Dictionary<string, int?> _typeCodes = new Dictionary<string, int?>(); |
| | | 16 | | |
| | | 17 | | public bool CanExecute(OrganizationRequest request) |
| | 42 | 18 | | { |
| | 42 | 19 | | return request is ExecuteFetchRequest; |
| | 42 | 20 | | } |
| | | 21 | | |
| | | 22 | | public OrganizationResponse Execute(OrganizationRequest request, XrmFakedContext ctx) |
| | 42 | 23 | | { |
| | 42 | 24 | | var executeFetchRequest = (ExecuteFetchRequest)request; |
| | | 25 | | |
| | 42 | 26 | | if (executeFetchRequest.FetchXml == null) |
| | 0 | 27 | | { |
| | 0 | 28 | | throw new FaultException<OrganizationServiceFault>(new OrganizationServiceFault(), "You need to provide |
| | | 29 | | } |
| | | 30 | | |
| | 42 | 31 | | var service = ctx.GetFakedOrganizationService(); |
| | | 32 | | |
| | 42 | 33 | | var retrieveMultiple = new RetrieveMultipleRequest() |
| | 42 | 34 | | { |
| | 42 | 35 | | Query = new FetchExpression(executeFetchRequest.FetchXml) |
| | 42 | 36 | | }; |
| | 42 | 37 | | var queryResult = (service.Execute(retrieveMultiple) as RetrieveMultipleResponse).EntityCollection; |
| | | 38 | | |
| | 42 | 39 | | XDocument doc = new XDocument(new XElement("resultset", |
| | 42 | 40 | | new XAttribute("morerecords", Convert.ToInt16(queryResult.MoreRecords)))); |
| | 42 | 41 | | if (queryResult.PagingCookie != null) |
| | 18 | 42 | | { |
| | 18 | 43 | | doc.Root.Add(new XAttribute("paging-cookie", queryResult.PagingCookie)); |
| | 18 | 44 | | } |
| | | 45 | | |
| | 42 | 46 | | var allowedAliases = new string[0]; |
| | | 47 | | |
| | 42 | 48 | | var fetchXmlDocument = XDocument.Parse(executeFetchRequest.FetchXml).Root; |
| | 42 | 49 | | if (fetchXmlDocument != null) |
| | 42 | 50 | | { |
| | 66 | 51 | | var linkedEntityName = fetchXmlDocument.Descendants("link-entity").Attributes("name").Select(a => a.Valu |
| | 48 | 52 | | allowedAliases = linkedEntityName.Concat(fetchXmlDocument.Descendants("link-entity").Attributes("alias") |
| | 42 | 53 | | } |
| | | 54 | | |
| | 510 | 55 | | foreach (var row in queryResult.Entities) |
| | 192 | 56 | | { |
| | 192 | 57 | | doc.Root.Add(CreateXmlResult(row, ctx, allowedAliases)); |
| | 192 | 58 | | } |
| | | 59 | | |
| | 42 | 60 | | var response = new ExecuteFetchResponse |
| | 42 | 61 | | { |
| | 42 | 62 | | Results = new ParameterCollection |
| | 42 | 63 | | { |
| | 42 | 64 | | { "FetchXmlResult", doc.ToString() } |
| | 42 | 65 | | } |
| | 42 | 66 | | }; |
| | | 67 | | |
| | 42 | 68 | | return response; |
| | 42 | 69 | | } |
| | | 70 | | |
| | | 71 | | private XElement CreateXmlResult(Entity entity, XrmFakedContext ctx, string[] allowedAliases) |
| | 192 | 72 | | { |
| | 192 | 73 | | var row = new XElement("result"); |
| | 192 | 74 | | var formattedValues = entity.FormattedValues; |
| | | 75 | | |
| | 1152 | 76 | | foreach (var entAtt in entity.Attributes) |
| | 288 | 77 | | { |
| | 288 | 78 | | var attribute = entAtt; |
| | | 79 | | |
| | | 80 | | // Depricated ExecuteFetch doesn't use implicitly numbered enitity aliases |
| | 288 | 81 | | if (attribute.Key.Contains(".")) |
| | 24 | 82 | | { |
| | 24 | 83 | | var alias = attribute.Key.Substring(0, attribute.Key.IndexOf(".", StringComparison.Ordinal)); |
| | 24 | 84 | | if (!allowedAliases.Contains(alias)) |
| | 18 | 85 | | { |
| | | 86 | | // The maximum amount of linked entities is 10, |
| | 18 | 87 | | var newAlias = alias.Substring(0, alias.Length - (!alias.EndsWith("10") ? 1 : 2)); |
| | 18 | 88 | | if (allowedAliases.Contains(newAlias)) |
| | 18 | 89 | | { |
| | 18 | 90 | | var newKey = attribute.Key.Split(new[] {'.'}, StringSplitOptions.RemoveEmptyEntries); |
| | 18 | 91 | | newKey[0] = newAlias; |
| | 18 | 92 | | attribute = new KeyValuePair<string, object>(string.Join(".", newKey), attribute.Value); |
| | 18 | 93 | | } |
| | | 94 | | else |
| | 0 | 95 | | { |
| | | 96 | | // unknow alias, just leave it |
| | 0 | 97 | | } |
| | 18 | 98 | | } |
| | 24 | 99 | | } |
| | | 100 | | |
| | 288 | 101 | | var attributeValueElement = AttributeValueToFetchResult(attribute, formattedValues, ctx); |
| | 288 | 102 | | if (attributeValueElement == null) |
| | 0 | 103 | | { |
| | 0 | 104 | | continue; |
| | | 105 | | } |
| | | 106 | | |
| | 288 | 107 | | row.Add(attributeValueElement); |
| | 288 | 108 | | } |
| | | 109 | | |
| | 192 | 110 | | return row; |
| | 192 | 111 | | } |
| | | 112 | | |
| | | 113 | | public XElement AttributeValueToFetchResult(KeyValuePair<string, object> entAtt, FormattedValueCollection format |
| | 343 | 114 | | { |
| | | 115 | | XElement attributeValueElement; |
| | 343 | 116 | | if (entAtt.Value == null) |
| | 0 | 117 | | return null; |
| | 343 | 118 | | if (entAtt.Value is DateTime?) |
| | 18 | 119 | | { |
| | 18 | 120 | | attributeValueElement = XElement.Parse(String.Format("<{0} date=\"{1:yyyy-MM-dd}\" time=\"{1:hh:mm tt}\" |
| | 18 | 121 | | } |
| | 325 | 122 | | else if (entAtt.Value is EntityReference) |
| | 24 | 123 | | { |
| | 24 | 124 | | var entRef = (EntityReference)entAtt.Value; |
| | 24 | 125 | | if (!_typeCodes.ContainsKey(entRef.LogicalName)) |
| | 24 | 126 | | { |
| | 24 | 127 | | var entType = RetrieveEntityRequestExecutor.GetEntityProxyType(entRef.LogicalName, ctx); |
| | 24 | 128 | | var typeCode = entType.GetField("EntityTypeCode").GetValue(null); |
| | | 129 | | |
| | 24 | 130 | | _typeCodes.Add(entRef.LogicalName, (int?)typeCode); |
| | 24 | 131 | | } |
| | | 132 | | |
| | 24 | 133 | | attributeValueElement = XElement.Parse(String.Format("<{0} dsc=\"0\" yomi=\"{1}\" name=\"{1}\" type=\"{3 |
| | 24 | 134 | | } |
| | 301 | 135 | | else if (entAtt.Value is bool?) |
| | 6 | 136 | | { |
| | 6 | 137 | | var boolValue = (bool?)entAtt.Value; |
| | | 138 | | |
| | 6 | 139 | | var formattedValue = boolValue.ToString(); |
| | 6 | 140 | | if (formattedValues.ContainsKey(entAtt.Key)) |
| | 0 | 141 | | formattedValue = formattedValues[entAtt.Key]; |
| | 6 | 142 | | attributeValueElement = XElement.Parse(String.Format("<{0} name=\"{1}\">{2}</{0}>", entAtt.Key, formatte |
| | 6 | 143 | | } |
| | 295 | 144 | | else if (entAtt.Value is OptionSetValue) |
| | 12 | 145 | | { |
| | 12 | 146 | | var osValue = (OptionSetValue)entAtt.Value; |
| | | 147 | | |
| | 12 | 148 | | var formattedValue = osValue.Value.ToString(); |
| | 12 | 149 | | if (formattedValues.ContainsKey(entAtt.Key)) |
| | 6 | 150 | | formattedValue = formattedValues[entAtt.Key]; |
| | 12 | 151 | | attributeValueElement = XElement.Parse(String.Format("<{0} name=\"{1}\" formattedvalue=\"{2}\">{2}</{0}> |
| | 12 | 152 | | } |
| | 283 | 153 | | else if (entAtt.Value is Enum) |
| | 0 | 154 | | { |
| | 0 | 155 | | var osValue = (Enum)entAtt.Value; |
| | | 156 | | |
| | 0 | 157 | | var formattedValue = osValue.ToString(); |
| | 0 | 158 | | if (formattedValues.ContainsKey(entAtt.Key)) |
| | 0 | 159 | | formattedValue = formattedValues[entAtt.Key]; |
| | 0 | 160 | | attributeValueElement = XElement.Parse(String.Format("<{0} name=\"{1}\" formattedvalue=\"{2}\">{2}</{0}> |
| | 0 | 161 | | } |
| | 283 | 162 | | else if (entAtt.Value is Money) |
| | 6 | 163 | | { |
| | 6 | 164 | | var moneyValue = (Money)entAtt.Value; |
| | | 165 | | |
| | 6 | 166 | | var formattedValue = moneyValue.Value.ToString(); |
| | 6 | 167 | | if (formattedValues.ContainsKey(entAtt.Key)) |
| | 0 | 168 | | formattedValue = formattedValues[entAtt.Key]; |
| | 6 | 169 | | attributeValueElement = XElement.Parse(String.Format("<{0} formattedvalue=\"{1}\">{2:0.##}</{0}>", entAt |
| | 6 | 170 | | } |
| | 277 | 171 | | else if (entAtt.Value is decimal?) |
| | 0 | 172 | | { |
| | 0 | 173 | | var decimalVal = (decimal?)entAtt.Value; |
| | | 174 | | |
| | 0 | 175 | | attributeValueElement = XElement.Parse(String.Format("<{0}>{1:0.####}</{0}>", entAtt.Key, decimalVal.Val |
| | 0 | 176 | | } |
| | 277 | 177 | | else if (entAtt.Value is AliasedValue) |
| | 30 | 178 | | { |
| | 30 | 179 | | var alliasedVal = entAtt.Value as AliasedValue; |
| | 30 | 180 | | attributeValueElement = AttributeValueToFetchResult(new KeyValuePair<string, object>(entAtt.Key, alliase |
| | 30 | 181 | | } |
| | 247 | 182 | | else if (entAtt.Value is Guid) |
| | 192 | 183 | | { |
| | 384 | 184 | | attributeValueElement = XElement.Parse(String.Format("<{0}>{1}</{0}>", entAtt.Key, entAtt.Value.ToString |
| | 192 | 185 | | } |
| | | 186 | | #if FAKE_XRM_EASY_9 |
| | 10 | 187 | | else if (entAtt.Value is OptionSetValueCollection) |
| | 1 | 188 | | { |
| | 1 | 189 | | var optionSetValueCollectionVal = entAtt.Value as OptionSetValueCollection; |
| | 5 | 190 | | var values = String.Join(",", optionSetValueCollectionVal.Select(o => o.Value).OrderBy(v => v)); |
| | 1 | 191 | | var serializedCollection = String.Join(",", "[-1", values, "-1]"); |
| | 1 | 192 | | attributeValueElement = XElement.Parse(String.Format("<{0} name=\"{1}\">{1}</{0}>", entAtt.Key, serializ |
| | 1 | 193 | | } |
| | | 194 | | #endif |
| | | 195 | | else |
| | 54 | 196 | | { |
| | 54 | 197 | | attributeValueElement = XElement.Parse(String.Format("<{0}>{1}</{0}>", entAtt.Key, entAtt.Value)); |
| | 54 | 198 | | } |
| | 343 | 199 | | return attributeValueElement; |
| | 343 | 200 | | } |
| | | 201 | | |
| | | 202 | | public Type GetResponsibleRequestType() |
| | 4270 | 203 | | { |
| | 4270 | 204 | | return typeof(ExecuteFetchRequest); |
| | 4270 | 205 | | } |
| | | 206 | | } |
| | | 207 | | } |