public void When_doing_a_crm_linq_query_with_an_equals_operator_record_is_returned()
        {
            var fakedContext = new XrmFakedContext();
            var guid1 = Guid.NewGuid();
            var guid2 = Guid.NewGuid();

            fakedContext.Initialize(new List<Entity>() {
                new Contact() { Id = guid1, FirstName = "Jordi" },
                new Contact() { Id = guid2, FirstName = "Other" }
            });

            var service = fakedContext.GetFakedOrganizationService();

            using (XrmServiceContext ctx = new XrmServiceContext(service))
            {
                var matches = (from c in ctx.CreateQuery<Contact>()
                               where c.FirstName.Equals("Jordi")
                               select c).ToList();

                Assert.True(matches.Count == 1);
                Assert.True(matches[0].FirstName.Equals("Jordi"));

                matches = (from c in ctx.CreateQuery<Contact>()
                               where c.FirstName == "Jordi" //Using now equality operator
                               select c).ToList();

                Assert.True(matches.Count == 1);
                Assert.True(matches[0].FirstName.Equals("Jordi"));
            }
            
        }
        public void When_executing_a_query_expression_with_2_filters_combined_with_an_or_filter_right_result_is_returned()
        {
            var context = new XrmFakedContext();
            var contact1 = new Entity("contact") { Id = Guid.NewGuid() }; contact1["fullname"] = "Contact 1"; contact1["firstname"] = "First 1";
            var contact2 = new Entity("contact") { Id = Guid.NewGuid() }; contact2["fullname"] = "Contact 2"; contact2["firstname"] = "First 2";

            context.Initialize(new List<Entity>() { contact1, contact2 });

            var qe = new QueryExpression() { EntityName = "contact" };
            qe.ColumnSet = new ColumnSet(true);
            

            var filter1 = new FilterExpression();
            filter1.AddCondition(new ConditionExpression("fullname", ConditionOperator.Equal, "Contact 1"));

            var filter2 = new FilterExpression();
            filter2.AddCondition(new ConditionExpression("fullname", ConditionOperator.Equal, "Contact 2"));

            qe.Criteria = new FilterExpression(LogicalOperator.Or);
            qe.Criteria.AddFilter(filter1);
            qe.Criteria.AddFilter(filter2);

            var result = XrmFakedContext.TranslateQueryExpressionToLinq(context, qe).ToList();

            Assert.True(result.Count == 2);
        }
        public void When_an_entity_is_created_with_an_empty_logical_name_an_exception_is_thrown()
        {
            var context = new XrmFakedContext();
            var service = context.GetFakedOrganizationService();

            var e = new Entity("") { Id = Guid.Empty };

            var ex = Assert.Throws<InvalidOperationException>(() => service.Create(e));
            Assert.Equal(ex.Message, "The LogicalName property must not be empty");
        }
        public static void When_using_proxy_types_assembly_the_attribute_metadata_is_inferred_from_the_proxy_types_assembly()
        {
            var fakedContext = new XrmFakedContext();
            fakedContext.ProxyTypesAssembly = Assembly.GetExecutingAssembly();

            var contact1 = new Entity("contact") { Id = Guid.NewGuid() }; contact1["fullname"] = "Contact 1"; contact1["firstname"] = "First 1";
            var contact2 = new Entity("contact") { Id = Guid.NewGuid() }; contact2["fullname"] = "Contact 2"; contact2["firstname"] = "First 2";

            fakedContext.Initialize(new List<Entity>() { contact1, contact2 });

            var guid = Guid.NewGuid();

            //Empty contecxt (no Initialize), but we should be able to query any typed entity without an entity not found exception

            var service = fakedContext.GetFakedOrganizationService();

            using (XrmServiceContext ctx = new XrmServiceContext(service))
            {
                var contact = (from c in ctx.CreateQuery<Contact>()
                               where c.FirstName.Equals("First 1")
                               select c).ToList();

                Assert.True(contact.Count == 1);
            }
        }
        public void When_the_create_task_activity_is_executed_a_task_is_created_in_the_context()
        {
            var fakedContext = new XrmFakedContext();
            fakedContext.ProxyTypesAssembly = Assembly.GetExecutingAssembly();

            var guid1 = Guid.NewGuid();
            var account = new Account() { Id = guid1 };
            fakedContext.Initialize(new List<Entity>() {
                account
            });

            //Inputs
            var inputs = new Dictionary<string, object>() {
                { "inputEntity", account.ToEntityReference() }
            };

            var result = fakedContext.ExecuteCodeActivity<CreateTaskActivity>(inputs);

            //The wf creates an activity, so make sure it is created
            var tasks = (from t in fakedContext.CreateQuery<Task>()
                         select t).ToList();

            //The activity creates a taks
            Assert.True(tasks.Count == 1);

            var output = result["taskCreated"] as EntityReference;

            //Task created contains the account passed as the regarding Id
            Assert.True(tasks[0].RegardingObjectId != null && tasks[0].RegardingObjectId.Id.Equals(guid1));

            //Same task created is returned
            Assert.Equal(output.Id, tasks[0].Id);
        }
        public void Should_Not_Change_Context_Objects_Without_Update()
        {
            var entityId = Guid.NewGuid();
            var context = new XrmFakedContext();
            var service = context.GetOrganizationService();

            context.Initialize(new[] {
                new Entity ("account")
                {
                    Id = entityId,
                    Attributes = new AttributeCollection
                    {
                        { "accountname", "Adventure Works" }
                    }
                }
            });

            var firstRetrieve = service.Retrieve("account", entityId, new ColumnSet(true));
            var secondRetrieve = service.Retrieve("account", entityId, new ColumnSet(true));

            firstRetrieve["accountname"] = "Updated locally";

            Assert.Equal("Updated locally", firstRetrieve["accountname"]);
            Assert.Equal("Adventure Works", secondRetrieve["accountname"]);
        }
        public static void When_a_query_by_attribute_is_executed_when_one_attribute_right_result_is_returned()
        {
            var context = new XrmFakedContext();
            var account = new Account() {Id = Guid.NewGuid(), Name = "Test"};
            var account2 = new Account() { Id = Guid.NewGuid(), Name = "Other account!" };
            context.Initialize(new List<Entity>()
            {
                account, account2
            });

            var service = context.GetFakedOrganizationService();

            QueryByAttribute query = new QueryByAttribute();
            query.Attributes.AddRange(new string[] { "name" });
            query.ColumnSet = new ColumnSet(new string[] { "name" });
            query.EntityName = Account.EntityLogicalName;
            query.Values.AddRange(new object[] { "Test" });

            //Execute using a request to test the OOB (XRM) message contracts
            RetrieveMultipleRequest request = new RetrieveMultipleRequest();
            request.Query = query;
            Collection<Entity> entityList = ((RetrieveMultipleResponse)service.Execute(request)).EntityCollection.Entities;

            Assert.True(entityList.Count == 1);
            Assert.Equal(entityList[0]["name"].ToString(), "Test");
        }
예제 #8
0
        public void Should_update_an_entity_when_calling_update()
        {
            var ctx = new XrmFakedContext();
            var logSystem = A.Fake<IDetailedLog>();
            var service = ctx.GetOrganizationService();

            //Arrange
            var contact = new Entity("contact") { Id = Guid.NewGuid() };
            contact["fullname"] = "Lionel Messi";

            ctx.Initialize(new Entity[]
            {
                contact
            });

            //Act
            var contactToUpdate = new Entity("contact") { Id = contact.Id };
            contactToUpdate["fullname"] = "Luis Suárez";

            var actions = new Actions(logSystem, service);
            actions.Update(contactToUpdate);

            //Assert
            var contacts = ctx.CreateQuery("contact").ToList();
            Assert.Equal(1, contacts.Count);
            Assert.Equal(contacts[0]["fullname"], "Luis Suárez");
        }
예제 #9
0
 public void When_initialising_the_context_twice_exception_is_thrown()
 {
     var context = new XrmFakedContext();
     var c = new Contact() { Id = Guid.NewGuid(), FirstName = "Lionel" };
     Assert.DoesNotThrow(() => context.Initialize(new List<Entity>() { c }));
     Assert.Throws<Exception>(() => context.Initialize(new List<Entity>() { c }));
 }
        public void When_doing_a_crm_linq_query_and_proxy_types_and_a_selected_attribute_returned_projected_entity_is_thesubclass()
        {
            var fakedContext = new XrmFakedContext();
            var guid1 = Guid.NewGuid();
            var guid2 = Guid.NewGuid();

            fakedContext.Initialize(new List<Entity>() {
                new Contact() { Id = guid1, FirstName = "Jordi" },
                new Contact() { Id = guid2, FirstName = "Other" }
            });

            var service = fakedContext.GetFakedOrganizationService();

            using (XrmServiceContext ctx = new XrmServiceContext(service))
            {
                var matches = (from c in ctx.CreateQuery<Contact>()
                               where c.FirstName.Equals("Jordi")
                               select new
                               {
                                   FirstName = c.FirstName,
                                   CrmRecord = c
                               }).ToList();

                Assert.True(matches.Count == 1);
                Assert.True(matches[0].FirstName.Equals("Jordi"));
                Assert.IsAssignableFrom(typeof(Contact), matches[0].CrmRecord);
                Assert.True(matches[0].CrmRecord.GetType() == typeof(Contact));
               
            }

        }
        public void When_doing_a_crm_linq_query_and_proxy_types_projection_must_be_applied_after_where_clause()
        {
            var fakedContext = new XrmFakedContext();
            fakedContext.ProxyTypesAssembly = Assembly.GetExecutingAssembly();

            var guid1 = Guid.NewGuid();
            var guid2 = Guid.NewGuid();

            fakedContext.Initialize(new List<Entity>() {
                new Contact() { Id = guid1, FirstName = "Jordi", LastName = "Montana" },
                new Contact() { Id = guid2, FirstName = "Other" }
            });

            var service = fakedContext.GetFakedOrganizationService();

            using (XrmServiceContext ctx = new XrmServiceContext(service))
            {
                var matches = (from c in ctx.CreateQuery<Contact>()
                               where c.LastName == "Montana"  //Should be able to filter by a non-selected attribute
                               select new
                               {
                                   FirstName = c.FirstName
                               }).ToList();

                Assert.True(matches.Count == 1);
                Assert.True(matches[0].FirstName.Equals("Jordi"));
            }
        }
        public void When_retrieve_is_invoked_with_a_null_columnset_exception_is_thrown()
        {
            var context = new XrmFakedContext();
            var service = context.GetFakedOrganizationService();

            var ex = Assert.Throws<InvalidOperationException>(() => service.Retrieve("account", Guid.NewGuid(), null));
            Assert.Equal(ex.Message, "The columnset parameter must not be null.");
        }
        public void When_retrieve_is_invoked_with_an_empty_guid_an_exception_is_thrown()
        {
            var context = new XrmFakedContext();
            var service = context.GetFakedOrganizationService();

            var ex = Assert.Throws<InvalidOperationException>(() => service.Retrieve("account", Guid.Empty, new ColumnSet()));
            Assert.Equal(ex.Message, "The id must not be empty.");
        }
        public void When_a_null_entity_is_created_an_exception_is_thrown()
        {
            var context = new XrmFakedContext();
            var service = context.GetFakedOrganizationService();

            var ex = Assert.Throws<InvalidOperationException>(() => service.Create(null));
            Assert.Equal(ex.Message, "The entity must not be null");
        }
예제 #15
0
        public void When_getting_a_fake_service_reference_it_uses_a_singleton_pattern()
        {
            var context = new XrmFakedContext();
            var service = context.GetFakedOrganizationService();
            var service2 = context.GetFakedOrganizationService();

            Assert.Equal(service, service2);
        }
예제 #16
0
        /// <summary>
        /// A fake retrieve method that will query the FakedContext to retrieve the specified
        /// entity and Guid, or null, if the entity was not found
        /// </summary>
        /// <param name="context">The faked context</param>
        /// <param name="fakedService">The faked service where the Retrieve method will be faked</param>
        /// <returns></returns>
        protected static void FakeRetrieve(XrmFakedContext context, IOrganizationService fakedService)
        {
            A.CallTo(() => fakedService.Retrieve(A<string>._, A<Guid>._, A<ColumnSet>._))
                .ReturnsLazily((string entityName, Guid id, ColumnSet columnSet) =>
                {
                    if (string.IsNullOrWhiteSpace(entityName))
                    {
                        throw new InvalidOperationException("The entity logical name must not be null or empty.");
                    }

                    if (id == Guid.Empty)
                    {
                        throw new InvalidOperationException("The id must not be empty.");
                    }

                    if (columnSet == null)
                    {
                        throw new InvalidOperationException("The columnset parameter must not be null.");
                    }

                    // Don't fail with invalid operation exception, if no record of this entity exists, but entity is known
                    if (!context.Data.ContainsKey(entityName))
                    {
                        if (context.ProxyTypesAssembly == null)
                        {
                            throw new InvalidOperationException(string.Format("The entity logical name {0} is not valid.",
                            entityName));
                        }

                        if (!context.ProxyTypesAssembly.GetTypes().Any(type => context.FindReflectedType(entityName) != null))
                        {
                            throw new InvalidOperationException(string.Format("The entity logical name {0} is not valid.",
                            entityName));
                        }
                    }
                    
                    //Entity logical name exists, so , check if the requested entity exists
                    if (context.Data.ContainsKey(entityName) && context.Data[entityName] != null
                        && context.Data[entityName].ContainsKey(id))
                    {
                        //Entity found => return only the subset of columns specified or all of them
                        if (columnSet.AllColumns)
                            return context.Data[entityName][id];
                        else
                        {
                            //Return the subset of columns requested only
                            var foundEntity = context.Data[entityName][id];
                            Entity projected = foundEntity.ProjectAttributes(columnSet,context);
                            return projected;
                        }
                    }
                    else
                    {
                        //Entity not found in the context => return null
                        throw new FaultException<OrganizationServiceFault>(new OrganizationServiceFault(), string.Format("{0} With Id = {1} Does Not Exist", entityName, id.ToString("D")));
                    }
                });
        }
        /// <summary>
        /// Fakes the RetrieveAttributeRequest that checks if an attribute exists for a given entity
        /// For simpicity, it asumes all attributes exist
        /// </summary>
        /// <param name="context"></param>
        /// <param name="fakedService"></param>
        protected static OrganizationResponse FakeRetrieveAttributeRequest(XrmFakedContext context, IOrganizationService fakedService, RetrieveAttributeRequest req)
        {
            var response = new RetrieveAttributeResponse
            {


            };
            return response;
        }
예제 #18
0
        // Test class constructor
        public AccountTests()
        {
            // Create fake service
            fakeContext = new XrmFakedContext();
            fakeService = fakeContext.GetOrganizationService();

            // Create real service
            realContext = new MyContext("XRM");
            realService = realContext.GetOrganizationService();
        }
예제 #19
0
        public void When_initializing_the_context_with_an_entity_with_an_empty_logical_name_an_exception_is_thrown()
        {
            var context = new XrmFakedContext();
            IEnumerable<Entity> data = new List<Entity>() {
                new Entity() { Id = Guid.NewGuid()}
            };

            var ex = Assert.Throws<InvalidOperationException>(() => context.Initialize(data));
            Assert.Equal(ex.Message, "An entity must not have a null or empty LogicalName property.");
        }
예제 #20
0
        public void When_an_entity_is_updated_with_an_empty_guid_an_exception_is_thrown()
        {
            var context = new XrmFakedContext();
            var service = context.GetFakedOrganizationService();

            var e = new Entity("account") { Id = Guid.Empty };

            var ex = Assert.Throws<InvalidOperationException>(() => service.Update(e));
            Assert.Equal(ex.Message, "The Id property must not be empty");
        }
예제 #21
0
        public void When_initializing_the_context_with_an_entity_with_an_empty_guid_an_exception_is_thrown()
        {
            var context = new XrmFakedContext();
            IEnumerable<Entity> data = new List<Entity>() {
                new Entity("account") { Id = Guid.Empty }
            };

            var ex = Assert.Throws<InvalidOperationException>(() => context.Initialize(data));
            Assert.Equal(ex.Message, "An entity with an empty Id can't be added");
        }
예제 #22
0
        public void When_initializing_the_context_with_a_dynamic_entity_with_a_primary_key_is_added_to_the_context()
        {
            var context = new XrmFakedContext();
            IEnumerable<Entity> data = new List<Entity>() {
                new Entity("account") { Id = Guid.NewGuid(), Attributes = new AttributeCollection { { "accountid", Guid.NewGuid() } }  }
            };

            Assert.DoesNotThrow(() => context.Initialize(data));
            Assert.True(context.Data.Count == 1);
            Assert.True(context.Data["account"].Count == 1);
        }
예제 #23
0
        public static void When_a_who_am_i_request_is_invoked_the_caller_id_is_returned()
        {
            var context = new XrmFakedContext();
            context.CallerId = new EntityReference() { Id = Guid.NewGuid(), Name = "Super Faked User" };

            var service = context.GetFakedOrganizationService();
            WhoAmIRequest req = new WhoAmIRequest();

            var response = service.Execute(req) as WhoAmIResponse;
            Assert.Equal(response.UserId, context.CallerId.Id);
        }
        public void When_adding_an_entity_the_returned_guid_must_not_be_empty_and_the_context_should_have_it()
        {
            var context = new XrmFakedContext();
            var service = context.GetFakedOrganizationService();

            var e = new Entity("account") { Id = Guid.Empty };
            var guid = service.Create(e);

            Assert.True(guid != Guid.Empty);
            Assert.True(context.Data.Count == 1);
            Assert.True(context.Data["account"].Count == 1);
        }
        public void When_the_account_number_plugin_is_executed_for_an_account_that_already_has_a_number_exception_is_thrown()
        {
            var fakedContext = new XrmFakedContext();

            var guid1 = Guid.NewGuid();
            var target = new Entity("account") { Id = guid1 };
            target["accountnumber"] = 69;

            //Execute our plugin against a target thatcontains the accountnumber attribute will throw exception
            Assert.Throws<InvalidPluginExecutionException>(() => fakedContext.ExecutePluginWithTarget<AccountNumberPlugin>(target));

        }
        public void Querying_a_dynamic_entity_not_present_in_the_context_should_return_no_records()
        {
            var context = new XrmFakedContext();

            var service = context.GetFakedOrganizationService();

            //Find the contact
            var contact = (from c in context.CreateQuery("contact")
                           select c).ToList();

            Assert.Equal(contact.Count, 0);
        }
예제 #27
0
        public void When_initializing_the_context_with_an_entity_it_should_have_default_createdon_createdby_modifiedon_and_modifiedby_attributes()
        {
            var context = new XrmFakedContext();
            var service = context.GetFakedOrganizationService();

            var e = new Entity("account") { Id = Guid.NewGuid() };
            context.Initialize(new List<Entity>() { e });

            Assert.True(e.Attributes.ContainsKey("createdon"));
            Assert.True(e.Attributes.ContainsKey("modifiedon"));
            Assert.True(e.Attributes.ContainsKey("createdby"));
            Assert.True(e.Attributes.ContainsKey("modifiedby"));
        }
        public void When_retrieve_is_invoked_with_an_empty_logical_name_an_exception_is_thrown()
        {
            var context = new XrmFakedContext();
            var service = context.GetFakedOrganizationService();

            var ex = Assert.Throws<InvalidOperationException>(() => service.Retrieve(null,Guid.Empty,new ColumnSet()));
            Assert.Equal(ex.Message, "The entity logical name must not be null or empty.");

            ex = Assert.Throws<InvalidOperationException>(() => service.Retrieve("", Guid.Empty, new ColumnSet()));
            Assert.Equal(ex.Message, "The entity logical name must not be null or empty.");

            ex = Assert.Throws<InvalidOperationException>(() => service.Retrieve("     ", Guid.Empty, new ColumnSet()));
            Assert.Equal(ex.Message, "The entity logical name must not be null or empty.");
        }
예제 #29
0
        public void When_initializing_the_context_with_an_entity_the_context_has_that_entity()
        {
            var context = new XrmFakedContext();
            var guid = Guid.NewGuid();

            IQueryable<Entity> data = new List<Entity>() {
                new Entity("account") { Id = guid }
            }.AsQueryable();

            context.Initialize(data);
            Assert.True(context.Data.Count == 1);
            Assert.True(context.Data["account"].Count == 1);
            Assert.Equal(context.Data["account"][guid], data.FirstOrDefault());
        }
        public void When_the_add_activity_with_constant_is_executed_without_a_specific_instance_result_is_the_two_summands()
        {
            var fakedContext = new XrmFakedContext();

            //Inputs
            var inputs = new Dictionary<string, object>() {
                { "firstSummand", 2 },
                { "secondSummand", 3 }
            };

            var result = fakedContext.ExecuteCodeActivity<AddActivityWithConstant>(inputs);

            Assert.True(((int)result["result"]).Equals(5));
        }
        internal static List <Entity> ProcessAggregateFetchXml(XrmFakedContext ctx, XDocument xmlDoc, List <Entity> resultOfQuery)
        {
            // Validate that <all-attributes> is not present,
            // that all attributes have groupby or aggregate, and an alias,
            // and that there is exactly 1 groupby.
            if (RetrieveFetchXmlNode(xmlDoc, "all-attributes") != null)
            {
                throw new Exception("Can't have <all-attributes /> present when using aggregate");
            }

            var ns = xmlDoc.Root.Name.Namespace;

            var entityName = RetrieveFetchXmlNode(xmlDoc, "entity")?.GetAttribute("name")?.Value;

            if (string.IsNullOrEmpty(entityName))
            {
                throw new Exception("Can't find entity name for aggregate query");
            }

            var aggregates = new List <FetchAggregate>();
            var groups     = new List <FetchGrouping>();

            foreach (var attr in xmlDoc.Descendants(ns + "attribute"))
            {
                //TODO: Find entity alias. Handle aliasedvalue in the query result.

                var alias       = attr.GetAttribute("alias")?.Value;
                var logicalName = attr.GetAttribute("name")?.Value;
                if (string.IsNullOrEmpty("alias"))
                {
                    throw new Exception("Missing alias for attribute in aggregate fetch xml");
                }
                if (string.IsNullOrEmpty("name"))
                {
                    throw new Exception("Missing name for attribute in aggregate fetch xml");
                }

                if (attr.IsAttributeTrue("groupby"))
                {
                    var dategrouping = attr.GetAttribute("dategrouping")?.Value;
                    if (dategrouping != null)
                    {
                        DateGroupType t;
                        if (!Enum.TryParse(dategrouping, true, out t))
                        {
                            throw new Exception("Unknown dategrouping value '" + dategrouping + "'");
                        }
                        groups.Add(new DateTimeGroup()
                        {
                            Type        = t,
                            OutputAlias = alias,
                            Attribute   = logicalName
                        });
                    }
                    else
                    {
                        groups.Add(new SimpleValueGroup()
                        {
                            OutputAlias = alias,
                            Attribute   = logicalName
                        });
                    }
                }
                else
                {
                    var agrFn = attr.GetAttribute("aggregate")?.Value;
                    if (string.IsNullOrEmpty(agrFn))
                    {
                        throw new Exception("Attributes must have be aggregated or grouped by when using aggregation");
                    }

                    FetchAggregate newAgr = null;
                    switch (agrFn?.ToLower())
                    {
                    case "count":
                        newAgr = new CountAggregate();
                        break;

                    case "countcolumn":
                        if (attr.IsAttributeTrue("distinct"))
                        {
                            newAgr = new CountDistinctAggregate();
                        }
                        else
                        {
                            newAgr = new CountColumnAggregate();
                        }
                        break;

                    case "min":
                        newAgr = new MinAggregate();
                        break;

                    case "max":
                        newAgr = new MaxAggregate();
                        break;

                    case "avg":
                        newAgr = new AvgAggregate();
                        break;

                    case "sum":
                        newAgr = new SumAggregate();
                        break;

                    default:
                        throw new Exception("Unknown aggregate function '" + agrFn + "'");
                    }

                    newAgr.OutputAlias = alias;
                    newAgr.Attribute   = logicalName;
                    aggregates.Add(newAgr);
                }
            }

            List <Entity> aggregateResult;

            if (groups.Any())
            {
                aggregateResult = ProcessGroupedAggregate(entityName, resultOfQuery, aggregates, groups);
            }
            else
            {
                aggregateResult = new List <Entity>();
                var ent = ProcessAggregatesForSingleGroup(entityName, resultOfQuery, aggregates);
                aggregateResult.Add(ent);
            }

            return(OrderAggregateResult(xmlDoc, aggregateResult.AsQueryable()));
        }
        public static IQueryable <Entity> TranslateLinkedEntityToLinq(XrmFakedContext context, LinkEntity le, IQueryable <Entity> query, ColumnSet previousColumnSet, string linkFromAlias = "")
        {
            var leAlias = string.IsNullOrWhiteSpace(le.EntityAlias) ? le.LinkToEntityName : le.EntityAlias;

            context.EnsureEntityNameExistsInMetadata(le.LinkFromEntityName);
            context.EnsureEntityNameExistsInMetadata(le.LinkToEntityName);

            if (!context.AttributeExistsInMetadata(le.LinkToEntityName, le.LinkToAttributeName))
            {
                OrganizationServiceFaultQueryBuilderNoAttributeException.Throw(le.LinkToAttributeName);
            }

            var inner = context.CreateQuery <Entity>(le.LinkToEntityName);

            //if (!le.Columns.AllColumns && le.Columns.Columns.Count == 0)
            //{
            //    le.Columns.AllColumns = true;   //Add all columns in the joined entity, otherwise we can't filter by related attributes, then the Select will actually choose which ones we need
            //}

            if (string.IsNullOrWhiteSpace(linkFromAlias))
            {
                linkFromAlias = le.LinkFromAttributeName;
            }
            else
            {
                linkFromAlias += "." + le.LinkFromAttributeName;
            }

            switch (le.JoinOperator)
            {
            case JoinOperator.Inner:
            case JoinOperator.Natural:
                query = query.Join(inner,
                                   outerKey => outerKey.KeySelector(linkFromAlias, context),
                                   innerKey => innerKey.KeySelector(le.LinkToAttributeName, context),
                                   (outerEl, innerEl) => outerEl
                                   .JoinAttributes(innerEl, new ColumnSet(true), leAlias, context));

                break;

            case JoinOperator.LeftOuter:
                query = query.GroupJoin(inner,
                                        outerKey => outerKey.KeySelector(le.LinkFromAttributeName, context),
                                        innerKey => innerKey.KeySelector(le.LinkToAttributeName, context),
                                        (outerEl, innerElemsCol) => new { outerEl, innerElemsCol })
                        .SelectMany(x => x.innerElemsCol.DefaultIfEmpty()
                                    , (x, y) => x.outerEl
                                    .JoinAttributes(y, new ColumnSet(true), leAlias, context));


                break;

            default:     //This shouldn't be reached as there are only 3 types of Join...
                throw new PullRequestException(string.Format("The join operator {0} is currently not supported. Feel free to implement and send a PR.", le.JoinOperator));
            }

            //Process nested linked entities recursively
            foreach (LinkEntity nestedLinkedEntity in le.LinkEntities)
            {
                if (string.IsNullOrWhiteSpace(le.EntityAlias))
                {
                    le.EntityAlias = le.LinkToEntityName;
                }

                query = TranslateLinkedEntityToLinq(context, nestedLinkedEntity, query, le.Columns, le.EntityAlias);
            }
            return(query);
        }
 public static QueryExpression TranslateFetchXmlToQueryExpression(XrmFakedContext context, string fetchXml)
 {
     return(TranslateFetchXmlDocumentToQueryExpression(context, ParseFetchXml(fetchXml)));
 }
        public static IQueryable <Entity> TranslateQueryExpressionToLinq(XrmFakedContext context, QueryExpression qe)
        {
            if (qe == null)
            {
                return(null);
            }

            //Start form the root entity and build a LINQ query to execute the query against the In-Memory context:
            context.EnsureEntityNameExistsInMetadata(qe.EntityName);

            IQueryable <Entity> query = null;

            query = context.CreateQuery <Entity>(qe.EntityName);

            //Add as many Joins as linked entities
            foreach (LinkEntity le in qe.LinkEntities)
            {
                query = TranslateLinkedEntityToLinq(context, le, query, qe.ColumnSet);
            }

            // Compose the expression tree that represents the parameter to the predicate.
            ParameterExpression entity = Expression.Parameter(typeof(Entity));
            var expTreeBody            = TranslateQueryExpressionFiltersToExpression(context, qe, entity);
            Expression <Func <Entity, bool> > lambda = Expression.Lambda <Func <Entity, bool> >(expTreeBody, entity);

            query = query.Where(lambda);

            //Project the attributes in the root column set  (must be applied after the where clause, not before!!)
            query = query.Select(x => x.Clone(x.GetType()).ProjectAttributes(qe, context));

            //Sort results
            if (qe.Orders != null)
            {
                if (qe.Orders.Count > 0)
                {
                    IOrderedQueryable <Entity> orderedQuery = null;

                    var order = qe.Orders[0];
                    if (order.OrderType == OrderType.Ascending)
                    {
                        orderedQuery = query.OrderBy(e => e.Attributes.ContainsKey(order.AttributeName) ? e[order.AttributeName] : null, new XrmOrderByAttributeComparer());
                    }
                    else
                    {
                        orderedQuery = query.OrderByDescending(e => e.Attributes.ContainsKey(order.AttributeName) ? e[order.AttributeName] : null, new XrmOrderByAttributeComparer());
                    }

                    //Subsequent orders should use ThenBy and ThenByDescending
                    for (var i = 1; i < qe.Orders.Count; i++)
                    {
                        var thenOrder = qe.Orders[i];
                        if (thenOrder.OrderType == OrderType.Ascending)
                        {
                            orderedQuery = orderedQuery.ThenBy(e => e.Attributes.ContainsKey(thenOrder.AttributeName) ? e[thenOrder.AttributeName] : null, new XrmOrderByAttributeComparer());
                        }
                        else
                        {
                            orderedQuery = orderedQuery.ThenByDescending(e => e[thenOrder.AttributeName], new XrmOrderByAttributeComparer());
                        }
                    }

                    query = orderedQuery;
                }
            }

            //Apply TopCount
            if (qe.TopCount != null)
            {
                query = query.Take(qe.TopCount.Value);
            }
            return(query);
        }
        protected static Expression TranslateConditionExpression(XrmFakedContext context, ConditionExpression c, ParameterExpression entity)
        {
            Expression attributesProperty = Expression.Property(
                entity,
                "Attributes"
                );


            //If the attribute comes from a joined entity, then we need to access the attribute from the join
            //But the entity name attribute only exists >= 2013
#if FAKE_XRM_EASY_2013 || FAKE_XRM_EASY_2015 || FAKE_XRM_EASY_2016 || FAKE_XRM_EASY_365
            string attributeName = "";

            if (!string.IsNullOrWhiteSpace(c.EntityName))
            {
                attributeName = c.EntityName + "." + c.AttributeName;
            }
            else
            {
                attributeName = c.AttributeName;
            }

            Expression containsAttributeExpression = Expression.Call(
                attributesProperty,
                typeof(AttributeCollection).GetMethod("ContainsKey", new Type[] { typeof(string) }),
                Expression.Constant(attributeName)
                );

            Expression getAttributeValueExpr = Expression.Property(
                attributesProperty, "Item",
                Expression.Constant(attributeName, typeof(string))
                );
#else
            Expression containsAttributeExpression = Expression.Call(
                attributesProperty,
                typeof(AttributeCollection).GetMethod("ContainsKey", new Type[] { typeof(string) }),
                Expression.Constant(c.AttributeName)
                );

            Expression getAttributeValueExpr = Expression.Property(
                attributesProperty, "Item",
                Expression.Constant(c.AttributeName, typeof(string))
                );
#endif



            Expression getNonBasicValueExpr = getAttributeValueExpr;

            switch (c.Operator)
            {
            case ConditionOperator.Equal:
            case ConditionOperator.Today:
            case ConditionOperator.Yesterday:
            case ConditionOperator.Tomorrow:
            case ConditionOperator.EqualUserId:
                return(TranslateConditionExpressionEqual(context, c, getNonBasicValueExpr, containsAttributeExpression));

            case ConditionOperator.NotEqualUserId:
                return(Expression.Not(TranslateConditionExpressionEqual(context, c, getNonBasicValueExpr, containsAttributeExpression)));

            case ConditionOperator.BeginsWith:
            case ConditionOperator.Like:
                return(TranslateConditionExpressionLike(c, getNonBasicValueExpr, containsAttributeExpression));

            case ConditionOperator.EndsWith:
                return(TranslateConditionExpressionEndsWith(c, getNonBasicValueExpr, containsAttributeExpression));

            case ConditionOperator.Contains:
                return(TranslateConditionExpressionContains(c, getNonBasicValueExpr, containsAttributeExpression));

            case ConditionOperator.NotEqual:
                return(Expression.Not(TranslateConditionExpressionEqual(context, c, getNonBasicValueExpr, containsAttributeExpression)));

            case ConditionOperator.DoesNotBeginWith:
            case ConditionOperator.DoesNotEndWith:
            case ConditionOperator.NotLike:
            case ConditionOperator.DoesNotContain:
                return(Expression.Not(TranslateConditionExpressionLike(c, getNonBasicValueExpr, containsAttributeExpression)));

            case ConditionOperator.Null:
                return(TranslateConditionExpressionNull(c, getNonBasicValueExpr, containsAttributeExpression));

            case ConditionOperator.NotNull:
                return(Expression.Not(TranslateConditionExpressionNull(c, getNonBasicValueExpr, containsAttributeExpression)));

            case ConditionOperator.GreaterThan:
                return(TranslateConditionExpressionGreaterThan(c, getNonBasicValueExpr, containsAttributeExpression));

            case ConditionOperator.GreaterEqual:
                return(TranslateConditionExpressionGreaterThanOrEqual(context, c, getNonBasicValueExpr, containsAttributeExpression));

            case ConditionOperator.LessThan:
                return(TranslateConditionExpressionLessThan(c, getNonBasicValueExpr, containsAttributeExpression));

            case ConditionOperator.LessEqual:
                return(TranslateConditionExpressionLessThanOrEqual(context, c, getNonBasicValueExpr, containsAttributeExpression));

            case ConditionOperator.In:
                return(TranslateConditionExpressionIn(c, getNonBasicValueExpr, containsAttributeExpression));

            case ConditionOperator.NotIn:
                return(Expression.Not(TranslateConditionExpressionIn(c, getNonBasicValueExpr, containsAttributeExpression)));

            case ConditionOperator.On:
                return(TranslateConditionExpressionEqual(context, c, getNonBasicValueExpr, containsAttributeExpression));

            case ConditionOperator.NotOn:
                return(Expression.Not(TranslateConditionExpressionEqual(context, c, getNonBasicValueExpr, containsAttributeExpression)));

            case ConditionOperator.OnOrAfter:
                return(Expression.Or(
                           TranslateConditionExpressionEqual(context, c, getNonBasicValueExpr, containsAttributeExpression),
                           TranslateConditionExpressionGreaterThan(c, getNonBasicValueExpr, containsAttributeExpression)));

            case ConditionOperator.OnOrBefore:
                return(Expression.Or(
                           TranslateConditionExpressionEqual(context, c, getNonBasicValueExpr, containsAttributeExpression),
                           TranslateConditionExpressionLessThan(c, getNonBasicValueExpr, containsAttributeExpression)));

            case ConditionOperator.Between:
                if (c.Values.Count != 2)
                {
                    throw new Exception("Between operator requires exactly 2 values.");
                }
                return(TranslateConditionExpressionBetween(c, getNonBasicValueExpr, containsAttributeExpression));

            case ConditionOperator.NotBetween:
                if (c.Values.Count != 2)
                {
                    throw new Exception("Not-Between operator requires exactly 2 values.");
                }
                return(Expression.Not(TranslateConditionExpressionBetween(c, getNonBasicValueExpr, containsAttributeExpression)));



            default:
                throw new PullRequestException(string.Format("Operator {0} not yet implemented for condition expression", c.Operator.ToString()));
            }
        }
 protected static Expression TranslateConditionExpressionLessThanOrEqual(XrmFakedContext context, ConditionExpression c, Expression getAttributeValueExpr, Expression containsAttributeExpr)
 {
     return(Expression.Or(
                TranslateConditionExpressionEqual(context, c, getAttributeValueExpr, containsAttributeExpr),
                TranslateConditionExpressionLessThan(c, getAttributeValueExpr, containsAttributeExpr)));
 }
        protected static Expression TranslateLinkedEntityFilterExpressionToExpression(XrmFakedContext context, LinkEntity le, ParameterExpression entity)
        {
            //In CRM 2011, condition expressions are at the LinkEntity level without an entity name
            //From CRM 2013, condition expressions were moved to outside the LinkEntity object at the QueryExpression level,
            //with an EntityName alias attribute

            //If we reach this point, it means we are translating filters at the Link Entity level (2011),
            //Therefore we need to prepend the alias attribute because the code to generate attributes for Joins (JoinAttribute extension) is common across versions

            if (le.LinkCriteria != null)
            {
                foreach (var ce in le.LinkCriteria.Conditions)
                {
                    var entityAlias = !string.IsNullOrEmpty(le.EntityAlias) ? le.EntityAlias : le.LinkToEntityName;
                    ce.AttributeName = entityAlias + "." + ce.AttributeName;
                }
            }

            return(TranslateFilterExpressionToExpression(context, le.LinkCriteria, entity));
        }
        /// <summary>
        /// A fake retrieve method that will query the FakedContext to retrieve the specified
        /// entity and Guid, or null, if the entity was not found
        /// </summary>
        /// <param name="context">The faked context</param>
        /// <param name="fakedService">The faked service where the Retrieve method will be faked</param>
        /// <returns></returns>
        protected static void FakeRetrieve(XrmFakedContext context, IOrganizationService fakedService)
        {
            A.CallTo(() => fakedService.Retrieve(A <string> ._, A <Guid> ._, A <ColumnSet> ._))
            .ReturnsLazily((string entityName, Guid id, ColumnSet columnSet) =>
            {
                if (string.IsNullOrWhiteSpace(entityName))
                {
                    throw new InvalidOperationException("The entity logical name must not be null or empty.");
                }

                if (id == Guid.Empty)
                {
                    throw new InvalidOperationException("The id must not be empty.");
                }

                if (columnSet == null)
                {
                    throw new InvalidOperationException("The columnset parameter must not be null.");
                }

                // Don't fail with invalid operation exception, if no record of this entity exists, but entity is known
                if (!context.Data.ContainsKey(entityName))
                {
                    if (context.ProxyTypesAssembly == null)
                    {
                        throw new InvalidOperationException($"The entity logical name {entityName} is not valid.");
                    }

                    if (!context.ProxyTypesAssembly.GetTypes().Any(type => context.FindReflectedType(entityName) != null))
                    {
                        throw new InvalidOperationException($"The entity logical name {entityName} is not valid.");
                    }
                }

                //Return the subset of columns requested only
                var reflectedType = context.FindReflectedType(entityName);

                //Entity logical name exists, so , check if the requested entity exists
                if (context.Data.ContainsKey(entityName) && context.Data[entityName] != null &&
                    context.Data[entityName].ContainsKey(id))
                {
                    //Entity found => return only the subset of columns specified or all of them
                    var foundEntity = context.Data[entityName][id].Clone(reflectedType);
                    if (columnSet.AllColumns)
                    {
                        foundEntity.ApplyDateBehaviour(context);
                        return(foundEntity);
                    }
                    else
                    {
                        var projected = foundEntity.ProjectAttributes(columnSet, context);
                        projected.ApplyDateBehaviour(context);
                        return(projected);
                    }
                }
                else
                {
                    // Entity not found in the context => FaultException
                    throw new FaultException <OrganizationServiceFault>(new OrganizationServiceFault(), $"{entityName} With Id = {id:D} Does Not Exist");
                }
            });
        }