Skip to content
This repository has been archived by the owner on Jun 16, 2024. It is now read-only.

Several fixes / improvements #2

Merged
merged 4 commits into from
Mar 14, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ where c.FirstName.Equals("Jordi")
A.CallTo(() => service.Execute(A<OrganizationRequest>.That.Matches(x => x is RetrieveMultipleRequest && ((RetrieveMultipleRequest)x).Query is QueryExpression))).MustHaveHappened();
}



[Fact]
public void When_doing_a_crm_linq_query_with_an_equals_operator_record_is_returned()
{
Expand Down Expand Up @@ -72,6 +74,70 @@ where c.FirstName.Equals("Jordi")

}

[Fact]
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));

}

}

[Fact]
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"));
}

}

[Fact]
public void When_doing_a_crm_linq_query_with_an_equals_operator_and_nulls_record_is_returned()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FakeItEasy;
using FakeXrmEasy;
using Xunit;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Client;
using Crm;
using Microsoft.Xrm.Sdk.Messages;
using System.Reflection; //TypedEntities generated code for testing



namespace FakeXrmEasy.Tests.FakeContextTests.LinqTests
{
public class MetadataInferenceTests
{
[Fact]
public static void When_using_proxy_types_assembly_the_entity_metadata_is_inferred_from_the_proxy_types_assembly()
{
var fakedContext = new XrmFakedContext();
fakedContext.ProxyTypesAssembly = Assembly.GetExecutingAssembly();

//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("Anything!")
select c).ToList();

Assert.True(contact.Count == 0);
}
}

[Fact]
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);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -111,5 +111,47 @@ public void When_executing_a_query_expression_with_contains_operator_right_resul

Assert.True(result.Count() == 2);
}

[Fact]
public void When_executing_a_query_expression_with_null_operator_right_result_is_returned()
{
var context = new XrmFakedContext();
var contact1 = new Entity("contact") { Id = Guid.NewGuid() }; contact1["fullname"] = "1 Contact";
var contact2 = new Entity("contact") { Id = Guid.NewGuid() }; contact2["fullname"] = null;
var contact3 = new Entity("contact") { Id = Guid.NewGuid() };

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

var qe = new QueryExpression() { EntityName = "contact" };
qe.ColumnSet = new ColumnSet(true);
qe.Criteria = new FilterExpression(LogicalOperator.And);
var condition = new ConditionExpression("fullname", ConditionOperator.Null);
qe.Criteria.AddCondition(condition);

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

Assert.True(result.Count() == 2);
}

[Fact]
public void When_executing_a_query_expression_with_a_not_null_operator_right_result_is_returned()
{
var context = new XrmFakedContext();
var contact1 = new Entity("contact") { Id = Guid.NewGuid() }; contact1["fullname"] = "1 Contact";
var contact2 = new Entity("contact") { Id = Guid.NewGuid() }; contact2["fullname"] = null;
var contact3 = new Entity("contact") { Id = Guid.NewGuid() };

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

var qe = new QueryExpression() { EntityName = "contact" };
qe.ColumnSet = new ColumnSet(true);
qe.Criteria = new FilterExpression(LogicalOperator.And);
var condition = new ConditionExpression("fullname", ConditionOperator.NotNull);
qe.Criteria.AddCondition(condition);

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

Assert.True(result.Count() == 1);
}
}
}
1 change: 1 addition & 0 deletions FakeXrmEasy.Tests/FakeXrmEasy.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
</Compile>
<Compile Include="FakeContextTests\LinqTests\FakeContextTestLinqQueries.cs" />
<Compile Include="FakeContextTests\FakeContextTestPlugins.cs" />
<Compile Include="FakeContextTests\LinqTests\MetadataInferenceTests.cs" />
<Compile Include="FakeContextTests\TranslateQueryExpressionTests\ConditionExpressionTests.cs" />
<Compile Include="FakeContextTests\TranslateQueryExpressionTests\FakeContextTestTranslateQueryExpression.cs" />
<Compile Include="FakeContextTests\FakeContextTestUpdate.cs" />
Expand Down
20 changes: 18 additions & 2 deletions FakeXrmEasy/Extensions/EntityExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,24 @@ public static Entity ProjectAttributes(this Entity e, ColumnSet columnSet, XrmFa
}
else
{
//Return selected list of attributes
var projected = new Entity(e.LogicalName) { Id = e.Id };
//Return selected list of attributes in a projected entity
Entity projected = null;

//However, if we are using proxy types, we must create a instance of the appropiate class
if (context.ProxyTypesAssembly != null)
{
var subClassType = context.FindReflectedType(e.LogicalName);
if (subClassType != null)
{
var instance = Activator.CreateInstance(subClassType);
projected = (Entity)instance;
projected.Id = e.Id;
}
else
projected = new Entity(e.LogicalName) { Id = e.Id }; //fallback to generic type if type not found
}
else
projected = new Entity(e.LogicalName) { Id = e.Id };

foreach (var attKey in columnSet.Columns)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ public static void Throw(string sMissingAttributeName)
{
ErrorCode = ErrorCode,
Message = string.Format("The attribute {0} does not exist on this entity.", sMissingAttributeName)
});
},
new FaultReason(string.Format("The attribute {0} does not exist on this entity.", sMissingAttributeName)));
}
}
}
40 changes: 36 additions & 4 deletions FakeXrmEasy/XrmFakedContext.Crud.cs
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,18 @@ protected static void FakeDelete(XrmFakedContext context, IOrganizationService f
#region Other protected methods
protected void EnsureEntityNameExistsInMetadata(string sEntityName)
{
if (!Data.ContainsKey(sEntityName))
//Entity metadata is checked differently when we are using a ProxyTypesAssembly => we can infer that from the generated types assembly
if (ProxyTypesAssembly != null)
{
var subClassType = FindReflectedType(sEntityName);
if (subClassType == null)
{
throw new Exception(string.Format("Entity {0} does not exist in the metadata cache", sEntityName));
}
}
else if (!Data.ContainsKey(sEntityName))
{
//No Proxy Types Assembly
throw new Exception(string.Format("Entity {0} does not exist in the metadata cache", sEntityName));
};
}
Expand Down Expand Up @@ -235,10 +245,32 @@ protected internal void AddEntity(Entity e)
AttributeMetadata.Add(e.LogicalName, new Dictionary<string, string>());

//Update attribute metadata
foreach (var attKey in e.Attributes.Keys)
if (ProxyTypesAssembly != null)
{
//If the context is using a proxy types assembly then we can just guess the metadata from the generated attributes
var type = FindReflectedType(e.LogicalName);
if (type != null)
{
var props = type.GetProperties();
foreach (var p in props)
{
if (!AttributeMetadata[e.LogicalName].ContainsKey(p.Name))
AttributeMetadata[e.LogicalName].Add(p.Name, p.Name);
}
}
else
throw new Exception(string.Format("Couldnt find reflected type for {0}", e.LogicalName));

}
else
{
if (!AttributeMetadata[e.LogicalName].ContainsKey(attKey))
AttributeMetadata[e.LogicalName].Add(attKey, attKey);
//If dynamic entities are being used, then the only way of guessing if a property exists is just by checking
//if the entity has the attribute in the dictionary
foreach (var attKey in e.Attributes.Keys)
{
if (!AttributeMetadata[e.LogicalName].ContainsKey(attKey))
AttributeMetadata[e.LogicalName].Add(attKey, attKey);
}
}
}

Expand Down
18 changes: 12 additions & 6 deletions FakeXrmEasy/XrmFakedContext.Queries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,25 +138,31 @@ public static IQueryable<Entity> TranslateQueryExpressionToLinq(XrmFakedContext
//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;

//var proxyType = context.FindReflectedType(qe.EntityName);
var query = context.CreateQuery<Entity>(qe.EntityName);
//if(proxyType != null)
// query = context.CreateQuery<proxyType.GetType()>(qe.EntityName);
//else
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);
}


//Project the attributes in the root column set
if(qe.ColumnSet != null && !qe.ColumnSet.AllColumns)
query = query.Select(x => x.ProjectAttributes(qe.ColumnSet, context));

// Compose the expression tree that represents the parameter to the predicate.
ParameterExpression entity = Expression.Parameter(typeof(Entity));
var expTreeBody = TranslateFilterExpressionToExpression(qe.Criteria, 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!!)
if (qe.ColumnSet != null && !qe.ColumnSet.AllColumns)
query = query.Select(x => x.ProjectAttributes(qe.ColumnSet, context));


return query;
}

Expand Down