Summary

Class:FakeXrmEasy.Extensions.EntityExtensions
Assembly:FakeXrmEasy
File(s):F:\Git\fake-xrm-easy\FakeXrmEasy.Shared\Extensions\EntityExtensions.cs
Covered lines:283
Uncovered lines:83
Coverable lines:366
Total lines:548
Line coverage:77.3%
Branch coverage:81.3%

Metrics

MethodCyclomatic ComplexitySequence CoverageBranch Coverage
AddAttribute(...)100
ProjectAttributes(...)1100100
ApplyDateBehaviour(...)7100100
ProjectAttributes(...)1584.7876.92
ProjectAttributes(...)1395.6592.31
RemoveNullAttributes(...)5100100
CloneAttribute(...)3396.2593.02
Clone(...)1210080
Clone(...)100
Clone(...)1310085.71
JoinAttributes(...)125036.36
JoinAttributes(...)1300
KeySelector(...)988.2480
Inject(...)1100100
SetValueIfEmpty(...)5100100
ToEntityReferenceWithKeyAttributes(...)1100100

File(s)

F:\Git\fake-xrm-easy\FakeXrmEasy.Shared\Extensions\EntityExtensions.cs

#LineLine coverage
 1using FakeXrmEasy.Metadata;
 2using Microsoft.Xrm.Sdk;
 3using Microsoft.Xrm.Sdk.Query;
 4using System;
 5using System.Collections.Generic;
 6using System.Linq;
 7
 8namespace FakeXrmEasy.Extensions
 9{
 10    public static class EntityExtensions
 11    {
 12        /// <summary>
 13        /// Extension method to add an attribute and return the entity itself
 14        /// </summary>
 15        /// <param name="e"></param>
 16        /// <param name="key"></param>
 17        /// <param name="value"></param>
 18        /// <returns></returns>
 19        public static Entity AddAttribute(this Entity e, string key, object value)
 020        {
 021            e.Attributes.Add(key, value);
 022            return e;
 023        }
 24
 25        /// <summary>
 26        /// Projects the attributes of entity e so that only the attributes specified in the columnSet are returned
 27        /// </summary>
 28        /// <param name="e"></param>
 29        /// <param name="columnSet"></param>
 30        /// <param name="alias"></param>
 31        /// <returns></returns>
 32        public static Entity ProjectAttributes(this Entity e, ColumnSet columnSet, XrmFakedContext context)
 15233        {
 15234            return ProjectAttributes(e, new QueryExpression() { ColumnSet = columnSet }, context);
 15235        }
 36
 37        public static void ApplyDateBehaviour(this Entity e, XrmFakedContext context)
 1645238        {
 39#if FAKE_XRM_EASY || FAKE_XRM_EASY_2013
 543840            return; //Do nothing... DateBehavior wasn't available for versions <= 2013
 41#else
 42
 1101443             if (context.DateBehaviour.Count == 0 || e.LogicalName == null || !context.DateBehaviour.ContainsKey(e.Logica
 963244            {
 963245                return;
 46            }
 47
 138248            var entityDateBehaviours = context.DateBehaviour[e.LogicalName];
 917849            foreach (var attribute in entityDateBehaviours.Keys)
 251650            {
 251651                 if (!e.Attributes.ContainsKey(attribute))
 235652                {
 235653                    continue;
 54                }
 55
 16056                 switch (entityDateBehaviours[attribute])
 57                {
 58                    case DateTimeAttributeBehavior.DateOnly:
 15259                        var currentValue = (DateTime)e[attribute];
 15260                        e[attribute] = new DateTime(currentValue.Year, currentValue.Month, currentValue.Day, 0, 0, 0, Da
 15261                        break;
 62
 63                    default:
 864                        break;
 65                }
 16066            }
 67#endif
 1645268        }
 69
 70        public static void ProjectAttributes(Entity e, Entity projected, LinkEntity le, XrmFakedContext context)
 1377871        {
 1377872             var sAlias = string.IsNullOrWhiteSpace(le.EntityAlias) ? le.LinkToEntityName : le.EntityAlias;
 73
 1377874             if (le.Columns.AllColumns)
 1275            {
 69676                foreach (var attKey in e.Attributes.Keys)
 33077                {
 33078                     if (attKey.StartsWith(sAlias + "."))
 13279                    {
 13280                        projected[attKey] = e[attKey];
 13281                    }
 33082                }
 83
 3684                foreach (var attKey in e.FormattedValues.Keys)
 085                {
 086                     if (attKey.StartsWith(sAlias + "."))
 087                    {
 088                        projected.FormattedValues[attKey] = e.FormattedValues[attKey];
 089                    }
 090                }
 1291            }
 92            else
 1376693            {
 4284294                foreach (var attKey in le.Columns.Columns)
 77295                {
 77296                    var linkedAttKey = sAlias + "." + attKey;
 77297                     if (e.Attributes.ContainsKey(linkedAttKey))
 71298                        projected[linkedAttKey] = e[linkedAttKey];
 99
 772100                     if (e.FormattedValues.ContainsKey(linkedAttKey))
 12101                        projected.FormattedValues[linkedAttKey] = e.FormattedValues[linkedAttKey];
 772102                }
 103
 13766104            }
 105
 41466106            foreach (var nestedLinkedEntity in le.LinkEntities)
 66107            {
 66108                ProjectAttributes(e, projected, nestedLinkedEntity, context);
 66109            }
 13778110        }
 111
 112        public static Entity ProjectAttributes(this Entity e, QueryExpression qe, XrmFakedContext context)
 31174113        {
 31174114             if (qe.ColumnSet == null || qe.ColumnSet.AllColumns)
 1723115            {
 1723116                return RemoveNullAttributes(e); //return all the original attributes
 117            }
 118            else
 29451119            {
 120                //Return selected list of attributes in a projected entity
 29451121                Entity projected = null;
 122
 123                //However, if we are using proxy types, we must create a instance of the appropiate class
 29451124                 if (context.ProxyTypesAssembly != null)
 2353125                {
 2353126                    var subClassType = context.FindReflectedType(e.LogicalName);
 2353127                     if (subClassType != null)
 2353128                    {
 2353129                        var instance = Activator.CreateInstance(subClassType);
 2353130                        projected = (Entity)instance;
 2353131                        projected.Id = e.Id;
 2353132                    }
 133                    else
 0134                        projected = new Entity(e.LogicalName) { Id = e.Id }; //fallback to generic type if type not foun
 2353135                }
 136                else
 27098137                    projected = new Entity(e.LogicalName) { Id = e.Id };
 138
 139
 97923140                foreach (var attKey in qe.ColumnSet.Columns)
 4791141                {
 142                    //Check if attribute really exists in metadata
 4791143                     if (!context.AttributeExistsInMetadata(e.LogicalName, attKey))
 12144                    {
 12145                        FakeOrganizationServiceFault.Throw(ErrorCodes.QueryBuilderNoAttribute, string.Format("The attrib
 0146                    }
 147
 4779148                     if (e.Attributes.ContainsKey(attKey) && e.Attributes[attKey] != null)
 2835149                    {
 2835150                        projected[attKey] = CloneAttribute(e[attKey], context);
 151
 2835152                        string formattedValue = "";
 153
 2835154                         if (e.FormattedValues.TryGetValue(attKey, out formattedValue))
 6155                        {
 6156                            projected.FormattedValues[attKey] = formattedValue;
 6157                        }
 2835158                    }
 4779159                }
 160
 161
 162                //Plus attributes from joins
 115741163                foreach (var le in qe.LinkEntities)
 13712164                {
 13712165                    ProjectAttributes(RemoveNullAttributes(e), projected, le, context);
 13712166                }
 29439167                return RemoveNullAttributes(projected);
 168            }
 31162169        }
 170
 171        public static Entity RemoveNullAttributes(Entity entity)
 44874172        {
 44874173            IList<string> nullAttributes = entity.Attributes
 294927174                .Where(attribute => attribute.Value == null ||
 294927175                                  (attribute.Value is AliasedValue && (attribute.Value as AliasedValue).Value == null))
 45061176                .Select(attribute => attribute.Key).ToList();
 134996177            foreach (var nullAttribute in nullAttributes)
 187178            {
 187179                entity.Attributes.Remove(nullAttribute);
 187180            }
 44874181            return entity;
 44874182        }
 183
 184        public static object CloneAttribute(object attributeValue, XrmFakedContext context = null)
 1988651185        {
 1988651186             if (attributeValue == null)
 555802187                return null;
 188
 1432849189            var type = attributeValue.GetType();
 1432849190             if (type == typeof(string))
 20690191                return new string((attributeValue as string).ToCharArray());
 1412159192             else if (type == typeof(EntityReference)
 1412159193#if FAKE_XRM_EASY
 1412159194                            || type == typeof(Microsoft.Xrm.Client.CrmEntityReference)
 1412159195#endif
 1412159196                    )
 555982197            {
 555982198                var original = (attributeValue as EntityReference);
 555982199                var clone = new EntityReference(original.LogicalName, original.Id);
 200
 555982201                 if (context != null && !string.IsNullOrEmpty(original.LogicalName) && context.EntityMetadata.ContainsKey
 555982202                    context.Data.ContainsKey(original.LogicalName) && context.Data[original.LogicalName].ContainsKey(ori
 54203                {
 54204                    clone.Name = context.Data[original.LogicalName][original.Id].GetAttributeValue<string>(context.Entit
 54205                }
 206                else
 555928207                {
 555928208                    clone.Name = CloneAttribute(original.Name) as string;
 555928209                }
 210
 211#if !FAKE_XRM_EASY && !FAKE_XRM_EASY_2013 && !FAKE_XRM_EASY_2015
 278769212                 if (original.KeyAttributes != null)
 278769213                {
 278769214                    clone.KeyAttributes = new KeyAttributeCollection();
 278781215                    clone.KeyAttributes.AddRange(original.KeyAttributes.Select(kvp => new KeyValuePair<string, object>(C
 278769216                }
 217#endif
 555982218                return clone;
 219            }
 856177220             else if (type == typeof(BooleanManagedProperty))
 18221            {
 18222                var original = (attributeValue as BooleanManagedProperty);
 18223                return new BooleanManagedProperty(original.Value);
 224            }
 856159225             else if (type == typeof(OptionSetValue))
 170061226            {
 170061227                var original = (attributeValue as OptionSetValue);
 170061228                return new OptionSetValue(original.Value);
 229            }
 686098230             else if (type == typeof(AliasedValue))
 121696231            {
 121696232                var original = (attributeValue as AliasedValue);
 121696233                return new AliasedValue(original.EntityLogicalName, original.AttributeLogicalName, CloneAttribute(origin
 234            }
 564402235             else if (type == typeof(Money))
 1125236            {
 1125237                var original = (attributeValue as Money);
 1125238                return new Money(original.Value);
 239            }
 563277240             else if (attributeValue.GetType() == typeof(EntityCollection))
 12241            {
 12242                var collection = attributeValue as EntityCollection;
 24243                return new EntityCollection(collection.Entities.Select(e => e.Clone(e.GetType())).ToList());
 244            }
 563265245             else if (attributeValue is IEnumerable<Entity>)
 6246            {
 6247                var enumerable = attributeValue as IEnumerable<Entity>;
 18248                return enumerable.Select(e => e.Clone(e.GetType())).ToArray();
 249            }
 250#if !FAKE_XRM_EASY
 470025251             else if (type == typeof(byte[]))
 5252            {
 5253                var original = (attributeValue as byte[]);
 5254                var copy = new byte[original.Length];
 5255                original.CopyTo(copy, 0);
 5256                return copy;
 257            }
 258#endif
 259#if FAKE_XRM_EASY_9
 94829260             else if (attributeValue is OptionSetValueCollection)
 292261            {
 292262                var original = (attributeValue as OptionSetValueCollection);
 292263                var copy = new OptionSetValueCollection(original.ToArray());
 292264                return copy;
 265            }
 266#endif
 562962267             else if (type == typeof(int) || type == typeof(Int64))
 4773268                return attributeValue; //Not a reference type
 558189269             else if (type == typeof(decimal))
 327270                return attributeValue; //Not a reference type
 557862271             else if (type == typeof(double))
 270272                return attributeValue; //Not a reference type
 557592273             else if (type == typeof(float))
 36274                return attributeValue; //Not a reference type
 557556275             else if (type == typeof(byte))
 0276                return attributeValue; //Not a reference type
 557556277             else if (type == typeof(float))
 0278                return attributeValue; //Not a reference type
 557556279             else if (type == typeof(bool))
 44620280                return attributeValue; //Not a reference type
 512936281             else if (type == typeof(Guid))
 174618282                return attributeValue; //Not a reference type
 338318283             else if (type == typeof(DateTime))
 338234284                return attributeValue; //Not a reference type
 84285             else if (attributeValue is Enum)
 84286                return attributeValue; //Not a reference type
 287
 0288            throw new Exception(string.Format("Attribute type not supported when trying to clone attribute '{0}'", type.
 1988651289        }
 290
 291        public static Entity Clone(this Entity e, XrmFakedContext context = null)
 56106292        {
 56106293            var cloned = new Entity(e.LogicalName);
 56106294            cloned.Id = e.Id;
 56106295            cloned.LogicalName = e.LogicalName;
 296
 56106297             if (e.FormattedValues != null)
 56106298            {
 56106299                var formattedValues = new FormattedValueCollection();
 168342300                foreach (var key in e.FormattedValues.Keys)
 12301                    formattedValues.Add(key, e.FormattedValues[key]);
 302
 56106303                cloned.Inject("FormattedValues", formattedValues);
 56106304            }
 305
 1046936306            foreach (var attKey in e.Attributes.Keys)
 439309307            {
 439309308                 cloned[attKey] = e[attKey] != null ? CloneAttribute(e[attKey], context) : null;
 439309309            }
 310#if !FAKE_XRM_EASY && !FAKE_XRM_EASY_2013 && !FAKE_XRM_EASY_2015
 84249311            foreach (var attKey in e.KeyAttributes.Keys)
 0312            {
 0313                 cloned.KeyAttributes[attKey] = e.KeyAttributes[attKey] != null ? CloneAttribute(e.KeyAttributes[attKey])
 0314            }
 315#endif
 56106316            return cloned;
 56106317        }
 318
 319        public static T Clone<T>(this Entity e) where T : Entity
 0320        {
 0321            return (T)e.Clone(typeof(T));
 0322        }
 323
 324        public static Entity Clone(this Entity e, Type t, XrmFakedContext context = null)
 98353325        {
 98353326             if (t == null)
 431327                return e.Clone(context);
 328
 97922329            var cloned = Activator.CreateInstance(t) as Entity;
 97922330            cloned.Id = e.Id;
 97922331            cloned.LogicalName = e.LogicalName;
 332
 97922333             if (e.FormattedValues != null)
 97922334            {
 97922335                var formattedValues = new FormattedValueCollection();
 293994336                foreach (var key in e.FormattedValues.Keys)
 114337                    formattedValues.Add(key, e.FormattedValues[key]);
 338
 97922339                cloned.Inject("FormattedValues", formattedValues);
 97922340            }
 341
 2034618342            foreach (var attKey in e.Attributes.Keys)
 870426343            {
 870426344                 cloned[attKey] = e[attKey] != null ? CloneAttribute(e[attKey], context) : null;
 870426345            }
 346
 347#if !FAKE_XRM_EASY && !FAKE_XRM_EASY_2013 && !FAKE_XRM_EASY_2015
 147819348            foreach (var attKey in e.KeyAttributes.Keys)
 9349            {
 9350                 cloned.KeyAttributes[attKey] = e.KeyAttributes[attKey] != null ? CloneAttribute(e.KeyAttributes[attKey])
 9351            }
 352#endif
 97922353            return cloned;
 98353354        }
 355
 356        /// <summary>
 357        /// Extension method to join the attributes of entity e and otherEntity
 358        /// </summary>
 359        /// <param name="e"></param>
 360        /// <param name="otherEntity"></param>
 361        /// <param name="attributes"></param>
 362        /// <returns></returns>
 363        public static Entity JoinAttributes(this Entity e, Entity otherEntity, ColumnSet columnSet, string alias, XrmFak
 15019364        {
 15196365             if (otherEntity == null) return e; //Left Join where otherEntity was not matched
 366
 14842367            otherEntity = otherEntity.Clone(); //To avoid joining entities from/to the same entities, which would cause 
 368
 14842369             if (columnSet.AllColumns)
 14842370            {
 286960371                foreach (var attKey in otherEntity.Attributes.Keys)
 121217372                {
 121217373                    e[alias + "." + attKey] = new AliasedValue(otherEntity.LogicalName, attKey, otherEntity[attKey]);
 121217374                }
 375
 44550376                foreach (var attKey in otherEntity.FormattedValues.Keys)
 12377                {
 12378                    e.FormattedValues[alias + "." + attKey] = otherEntity.FormattedValues[attKey];
 12379                }
 14842380            }
 381            else
 0382            {
 383                //Return selected list of attributes
 0384                foreach (var attKey in columnSet.Columns)
 0385                {
 0386                     if (!context.AttributeExistsInMetadata(otherEntity.LogicalName, attKey))
 0387                    {
 0388                        FakeOrganizationServiceFault.Throw(ErrorCodes.QueryBuilderNoAttribute, string.Format("The attrib
 0389                    }
 390
 0391                     if (otherEntity.Attributes.ContainsKey(attKey))
 0392                    {
 0393                        e[alias + "." + attKey] = new AliasedValue(otherEntity.LogicalName, attKey, otherEntity[attKey])
 0394                    }
 395                    else
 0396                    {
 0397                        e[alias + "." + attKey] = new AliasedValue(otherEntity.LogicalName, attKey, null);
 0398                    }
 399
 0400                     if (otherEntity.FormattedValues.ContainsKey(attKey))
 0401                    {
 0402                        e.FormattedValues[alias + "." + attKey] = otherEntity.FormattedValues[attKey];
 0403                    }
 0404                }
 0405            }
 14842406            return e;
 15019407        }
 408
 409        public static Entity JoinAttributes(this Entity e, IEnumerable<Entity> otherEntities, ColumnSet columnSet, strin
 0410        {
 0411            foreach (var otherEntity in otherEntities)
 0412            {
 0413                var otherClonedEntity = otherEntity.Clone(); //To avoid joining entities from/to the same entities, whic
 414
 0415                 if (columnSet.AllColumns)
 0416                {
 0417                    foreach (var attKey in otherClonedEntity.Attributes.Keys)
 0418                    {
 0419                        e[alias + "." + attKey] = new AliasedValue(otherEntity.LogicalName, attKey, otherClonedEntity[at
 0420                    }
 421
 0422                    foreach (var attKey in otherEntity.FormattedValues.Keys)
 0423                    {
 0424                        e.FormattedValues[alias + "." + attKey] = otherEntity.FormattedValues[attKey];
 0425                    }
 0426                }
 427                else
 0428                {
 429                    //Return selected list of attributes
 0430                    foreach (var attKey in columnSet.Columns)
 0431                    {
 0432                         if (!context.AttributeExistsInMetadata(otherEntity.LogicalName, attKey))
 0433                        {
 0434                            FakeOrganizationServiceFault.Throw(ErrorCodes.QueryBuilderNoAttribute, string.Format("The at
 0435                        }
 436
 0437                         if (otherClonedEntity.Attributes.ContainsKey(attKey))
 0438                        {
 0439                            e[alias + "." + attKey] = new AliasedValue(otherEntity.LogicalName, attKey, otherClonedEntit
 0440                        }
 441                        else
 0442                        {
 0443                            e[alias + "." + attKey] = new AliasedValue(otherEntity.LogicalName, attKey, null);
 0444                        }
 445
 0446                         if (otherEntity.FormattedValues.ContainsKey(attKey))
 0447                        {
 0448                            e.FormattedValues[alias + "." + attKey] = otherEntity.FormattedValues[attKey];
 0449                        }
 0450                    }
 0451                }
 0452            }
 0453            return e;
 0454        }
 455
 456        /// <summary>
 457        /// Returns the key for the attribute name selected (could an entity reference or a primary key or a guid)
 458        /// </summary>
 459        /// <param name="e"></param>
 460        /// <param name="sAttributeName"></param>
 461        /// <returns></returns>
 462        public static object KeySelector(this Entity e, string sAttributeName, XrmFakedContext context)
 30077463        {
 30077464             if (sAttributeName.Contains("."))
 192465            {
 466                //Do not lowercase the alias prefix
 192467                var splitted = sAttributeName.Split('.');
 192468                sAttributeName = string.Format("{0}.{1}", splitted[0], splitted[1].ToLower());
 192469            }
 470            else
 29885471            {
 29885472                sAttributeName = sAttributeName.ToLower();
 29885473            }
 474
 30077475             if (!e.Attributes.ContainsKey(sAttributeName))
 174476            {
 477                //Check if it is the primary key
 174478                 if (sAttributeName.Contains("id") &&
 174479                   e.LogicalName.ToLower().Equals(sAttributeName.Substring(0, sAttributeName.Length - 2)))
 0480                {
 0481                    return e.Id;
 482                }
 174483                return Guid.Empty; //Atrribute is null or doesn´t exists so it can´t be joined
 484            }
 485
 29903486            object keyValue = null;
 487            AliasedValue aliasedValue;
 29903488             if ((aliasedValue = e[sAttributeName] as AliasedValue) != null)
 192489            {
 192490                keyValue = aliasedValue.Value;
 192491            }
 492            else
 29711493            {
 29711494                keyValue = e[sAttributeName];
 29711495            }
 496
 29903497            EntityReference entityReference = keyValue as EntityReference;
 29903498             if (entityReference != null)
 14494499                return entityReference.Id;
 500
 15409501            OptionSetValue optionSetValue = keyValue as OptionSetValue;
 15409502             if (optionSetValue != null)
 0503                return optionSetValue.Value;
 504
 15409505            Money money = keyValue as Money;
 15409506             if (money != null)
 0507                return money.Value;
 508
 15409509            return keyValue;
 30077510        }
 511
 512        /// <summary>
 513        /// Extension method to "hack" internal set properties on sealed classes via reflection
 514        /// </summary>
 515        /// <param name="e"></param>
 516        /// <param name="property"></param>
 517        /// <param name="value"></param>
 518        public static void Inject(this Entity e, string property, object value)
 154064519        {
 154064520            e.GetType().GetProperty(property).SetValue(e, value, null);
 154064521        }
 522
 523        public static void SetValueIfEmpty(this Entity e, string property, object value)
 170478524        {
 170478525            var containsKey = e.Attributes.ContainsKey(property);
 170478526             if (!containsKey || containsKey && e[property] == null)
 170189527            {
 170189528                e[property] = value;
 170189529            }
 170478530        }
 531
 532        /// <summary>
 533        /// ToEntityReference implementation which converts an entity into an entity reference with key attribute info a
 534        /// </summary>
 535        /// <param name="e">Entity to convert to an Entity Reference</param>
 536        /// <returns></returns>
 537        public static EntityReference ToEntityReferenceWithKeyAttributes(this Entity e)
 342538        {
 342539            var result = e.ToEntityReference();
 540#if !FAKE_XRM_EASY && !FAKE_XRM_EASY_2013 && !FAKE_XRM_EASY_2015
 184541            result.KeyAttributes = e.KeyAttributes;
 542#endif
 342543            return result;
 342544        }
 545
 546
 547    }
 548}